线性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 ...
随机推荐
- 关于UIGestureRecognizerState
UIGestureRecognizerState的定义如下 typedef enum { UIGestureRecognizerStatePossible, UIGestureRecognizerSt ...
- php中实现记住密码下次自动登录的例子
这篇文章主要介绍了php中实现记住密码下次自动登录的例子,本文使用cookie实现记住密码和自动登录功能,需要的朋友可以参考下 做网站的时候经常会碰到要实现记住密码,下次自动登录,一周内免登陆,一个月 ...
- 定时器Enable Disable控制
问题:定时器如何控制它一会可用一会不可用,根据某个业务需求,比如:一个控制台程序扫描表中某个条件的数据,处理数据,控制台分布式部署,当主机宕机后,从机扫描定时器需要可用,当主机复活后,从机的扫描定时器 ...
- Java md5加密 控制台传入与web传入参数 结果不匹配 || 相同字符串加密结果不同,如何保证JAVA MD5加密结果在不同的环境下都相同
开发中遇到md5加密不一致问题,排除了上下文编码,加密内容问题. 爬了各类资料,最终找到了原因. /** 对字符串进行MD5加密 */ private static String encodeByMD ...
- css背景图等比例缩放,盒子随背景图等比例缩放
很多时候我们给网站了一个大banner,但是随着屏幕的变化,背景会变形,我们知道background-size可以实现背景图等比例缩放,但是,我们想让下面的盒子根据缩放后背景图的高度,也能自动向上挤. ...
- Jackson(ObjectMapper)的简单使用(可转xml)
参考文章:http://www.cnblogs.com/hoojo/archive/2011/04/22/2024628.html (原文章更详细哦,且有介绍xml与java对象的互转) 参考文章作 ...
- java-RAC Oracle 连接字符串
昨天在访问oracle数据库取数据时遇到一个问题: 上网搜索一下发现是我访问的数据库做了RAC,原有的数据库连接字符串不适用,原来的连接字符串如下所示: 使用下面的字符串解决了该问题: String ...
- CentOS7安装ipython
python版本:2.7.5 yum install -y python2-pip.noarchyum install -y python-develpip install ipython==5.4. ...
- repr方法字符串输出实例对象的值
#coding=utf-8 #repr方法字符串输出实例对象的值 class CountFromBy(object): def __init__(self, val=0, incr=1): self. ...
- #pragma init_seg
先进后出原则,最先初始化的最后析构! 1.C++中全局对象.变量的构造函数调用顺序是跟声明有一定关系的,即在同一个文件中先声明的先调用.对于不同文件中的全局对象.变量,它们的构造函数调用顺序是未定义的 ...