线性DP总结(LIS,LCS,LCIS,最长子段和)
做了一段时间的线性dp的题目是时候做一个总结
线性动态规划无非就是在一个数组上搞嘛,
首先看一个最简单的问题:
一,最长字段和
下面为状态转移方程
for(int i=2;i<=n;i++)
{
if(dp[i-1]>=0)
dp[i]=dp[i-1]+a[i];
else
dp[i]=a[i];
}
例题
裸的最长字段和
可以用滚动数组,下面是用滚动数组写的
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <stdlib.h>
using namespace std;
int n;
int a;
int sum;
int _begin;
int _end;
int main()
{
int t;
scanf("%d",&t);
int k=0;
while(t--)
{
int max;
int x=1;
scanf("%d%d",&n,&a);
sum=a;
max=a;
_begin=_end=1;
for(int i=2;i<=n;i++)
{
scanf("%d",&a);
if(sum>=0)
{
sum+=a;
}
else
{
sum=a;
x=i;
}
if(max<sum)
{
max=sum;
_begin=x;
_end=i;
}
}
cout<<"Case "<<++k<<":"<<endl<<max<<" "<<_begin<<" "<<_end<<endl;
if(t)
cout<<endl;
}
return 0;
}
升级一下,二维的呢?也就是求最大子矩阵和
状态转移方程,其实就是将一维转换成二维的,如何转换呢?操作就是将第一行每个数加上第二行对应的每个数,变成一维的进行dp,再加上第三行对应的每个数,进行DP。起点行分别枚举从1到n。
for(int i=1;i<=n;i++)
{
memset(b,0,sizeof(b));
memset(dp,0,sizeof(dp));
for(int k=i;k<=n;k++)
{
for(int j=1;j<=n;j++)
{
b[j]+=a[k][j];
if(dp[j-1]>=0)
dp[j]=dp[j-1]+b[j];
else
dp[j]=b[j];
if(sum<dp[j])
sum=dp[j];
}
}
}
#include <iostream>
#include <math.h>
#include <string.h>
#include <algorithm>
#include <stdlib.h>
using namespace std;
int a[105][105];
int n;
int dp[105];
int b[105];
int sum;
int main()
{
while(scanf("%d",&n)!=EOF)
{
sum=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&a[i][j]);
}
}
for(int i=1;i<=n;i++)
{
memset(b,0,sizeof(b));
memset(dp,0,sizeof(dp));
for(int k=i;k<=n;k++)
{
for(int j=1;j<=n;j++)
{
b[j]+=a[k][j];
if(dp[j-1]>=0)
dp[j]=dp[j-1]+b[j];
else
dp[j]=b[j];
if(sum<dp[j])
sum=dp[j];
}
}
}
printf("%d\n",sum);
}
return 0;
}
接下来就是LIS问题,LIS就是最长下降子序列或者是最长上升子序列。有O(n^2)效率的算法,也有O(nlogn)效率的算法。
先说O(n^2)效率的算法。很简单,DP[j] = MAX(DP[i]) + 1 满足条件a[j] > a[i]
转态转移方程
for(int i=2;i<=n+1;i++)
{
int num=0;
for(int j=i-1;j>=1;j--)
{
if(a[i]>a[j])
num=max(num,dp[j]);
}
dp[i]=num+1;
}
O(nlogn)效率的算法,参考这篇博文
博文
其实过程很简单,以最长上升子序列为例。dp数组的最终长度就是最长上升子序列,遍历a数组,a[i]如果比dp数组最后一个元素大,即a[i]>dp[len]则直接加入dp数组里。否则就要二分查找到第一个大于a[i]的dp[j],然后将dp[j]换成a[i],最终的dp数组的长度就是答案。
例题
#include <iostream>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <stdlib.h>
using namespace std;
#define MAX 40000
int a[MAX+5];
int dp[MAX+5];
int n;
int search(int num,int l,int r)
{
int mid;
while(l<=r)
{
mid=(l+r)/2;
if(num>=dp[mid])
l=mid+1;
else
r=mid-1;
}
return l;
}
int main()
{
int cas=0;
int x,y;
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
memset(dp,0,sizeof(dp));
dp[1]=a[1];
int len=1;
for(int i=2;i<=n;i++)
{
if(a[i]>=dp[len])
dp[++len]=a[i];
else
{
int pos=search(a[i],1,len);
dp[pos]=a[i];
}
}
printf("%d\n",len);
}
return 0;
}
还有一个比较相似的求最长连续上升子序列或最长连续下降子序列。求解这个就不用DP了,应该用线段树。
接下来就是LCS,最长公共子序列问题,这个也有O(n^2)的效率和O(nlogn)的效率
O(n^2)效率的看代码
for(int i=0;i<len1;i++)
{
for(int j=0;j<len2;j++)
{
if(s1[i]==s2[j])
dp[i+1][j+1]=dp[i][j]+1;
else
dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j]);
}
}
O(nlogn)效率是把LCS转化成LIS问题
a[] = {a, b, c,} b[] = {a,b,c,b,a,d},那么a中的a,b,c在b中出现的位置分别就是{0,4},{1,3},{2}分别按降序排列后代入a序列就是{4,0,2,3,1},
线性DP总结(LIS,LCS,LCIS,最长子段和)的更多相关文章
- LIS+LCS+LCIS
PS:本篇博文均采用宏#define FOR(i, a, n) for(i = a; i <= n; ++i) LIS:最长上升子序列 废话不多说:http://baike.baidu.com/ ...
- LIS LCS LCIS (主要过一遍,重在做题)
只详细讲解LCS和LCIS,别的不讲-做题优先. 菜鸟能力有限写不了题解,可以留评论,我给你找博客. 先得理解最长上升子序列吧,那个HDOJ拦截导弹系列可以做一下,然后用o(n)log(n)的在做一遍 ...
- LIS && LCS && LCIS && LPS && MCS模板
1. LIS (Longest Increasing Subsequence) O (n^2): /* LIS(Longest Increasing Subsequence) 最长上升子序列 O (n ...
- 8.3 LIS LCS LCIS(完结了==!)
感觉这个专题真不好捉,伤心了,慢慢啃吧,孩纸 地址http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28195#overview 密码 ac ...
- LIS&&LCS&&LCIS
LIS #include<bits/stdc++.h> using namespace std; int n,a[100005],b[100005],ji; int main(){ cin ...
- HDU-1160-FatMouse's Speed(线性DP,LIS)
FatMouse's Speed Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- 1. 线性DP 300. 最长上升子序列 (LIS)
最经典单串: 300. 最长上升子序列 (LIS) https://leetcode-cn.com/problems/longest-increasing-subsequence/submission ...
- 最长递增子序列(lis)最长公共子序列(lcs) 最长公共上升子序列(lics)
lis: 复杂度nlgn #include<iostream> #include<cstdio> using namespace std; ],lis[],res=; int ...
- 最长回文子序列LCS,最长递增子序列LIS及相互联系
最长公共子序列LCS Lintcode 77. 最长公共子序列 LCS问题是求两个字符串的最长公共子序列 \[ dp[i][j] = \left\{\begin{matrix} & max(d ...
随机推荐
- 几个实用的sublime text 2的快捷键
Sublime text快捷键 Sublime text 2是一款轻量.简洁.高效.跨平台的编辑器,他适合编写javascript,html,css,php,paython等等, 作为程序员,编码效率 ...
- iOS - 解决Unable to add a source with url `https://github.com/CocoaPods/Specs.git` named
1 本来cocopods没有问题,最近创建项目,利用cocopods导入第三方库的时候,出现如下错误: [!] Unable to add a source with url `https://gi ...
- CPU特性漏洞测试(Meltdown and Spectre)
2018年1月4日,国外安全研究人员披露了名为"Meltdown"和"Spectre"两组CPU特性漏洞,该漏洞波及到近20年的Intel, AMD, Qual ...
- 关于bat中使用rar压缩命令
数据库备份,导出的dmp 文件比较大,需要压缩,压缩后大小能变为原来十分之一左右吧. 写的是批处理的语句,每天调用,自动导出dmp 文件,压缩删除原文件. 首先写下路径 先将压缩软件的路径写入系统的环 ...
- C语言变量的存储布局
分析以下代码中变量存储空间如何分配: //MemSeg.c: 代码无意义,仅供分析用 #include <stdio.h> #include <stdlib.h> //mall ...
- 10分钟10行代码开发APP(delphi 应用案例)
总结一下用到的知识(开发环境安装配置不计算在内): 第六章 使用不同风格的按钮: 第十七章 让布局适应不同大小与方向的窗体: 第二十五章 使用 dbExpress访问 InterBase ToGo ...
- Delphi 10 Seattle 小票打印控件TQ_Printer
TQ_Printrer控件,是一个为方便需要控制打印命令而设计的跨平台专用控件,已包含标准ESC/POS打印控制的基本指令在内(这些基本指令已能很好的满足多数项目使用). TQ_Printrer控件让 ...
- 【Spring源码深度解析学习系列】Bean的加载(六)
Bean的加载所涉及到的大致步骤: 1)转换对应beanName 为什么需要转换beanName呢?因为传入的参数可能是别名,也可能是FactoryBean,所以需要一系列的解析,这些解析内容包括如下 ...
- C++ 输入输出流 文本文件 二进制文件读写
文本文件/ASCII文件(能直接显示内容,费存储空间):文件中每一个字节中均以ASCII代码形式存放数据,即一个字节存放一个字符,这个文件就是ASCII文件或称字符文件. 二进制文件(不能显示内容,节 ...
- C# 反射的深入了解
Assembly.Load("")的使用说明如下; 并不是命名空间.常用的是程序集名称,也就是dll的名称 关于反射Assembly.Load("程序集" ...