做了一段时间的线性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,最长子段和)的更多相关文章

  1. LIS+LCS+LCIS

    PS:本篇博文均采用宏#define FOR(i, a, n) for(i = a; i <= n; ++i) LIS:最长上升子序列 废话不多说:http://baike.baidu.com/ ...

  2. LIS LCS LCIS (主要过一遍,重在做题)

    只详细讲解LCS和LCIS,别的不讲-做题优先. 菜鸟能力有限写不了题解,可以留评论,我给你找博客. 先得理解最长上升子序列吧,那个HDOJ拦截导弹系列可以做一下,然后用o(n)log(n)的在做一遍 ...

  3. LIS && LCS && LCIS && LPS && MCS模板

    1. LIS (Longest Increasing Subsequence) O (n^2): /* LIS(Longest Increasing Subsequence) 最长上升子序列 O (n ...

  4. 8.3 LIS LCS LCIS(完结了==!)

    感觉这个专题真不好捉,伤心了,慢慢啃吧,孩纸 地址http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28195#overview 密码  ac ...

  5. LIS&&LCS&&LCIS

    LIS #include<bits/stdc++.h> using namespace std; int n,a[100005],b[100005],ji; int main(){ cin ...

  6. HDU-1160-FatMouse's Speed(线性DP,LIS)

    FatMouse's Speed Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  7. 1. 线性DP 300. 最长上升子序列 (LIS)

    最经典单串: 300. 最长上升子序列 (LIS) https://leetcode-cn.com/problems/longest-increasing-subsequence/submission ...

  8. 最长递增子序列(lis)最长公共子序列(lcs) 最长公共上升子序列(lics)

    lis: 复杂度nlgn #include<iostream> #include<cstdio> using namespace std; ],lis[],res=; int ...

  9. 最长回文子序列LCS,最长递增子序列LIS及相互联系

    最长公共子序列LCS Lintcode 77. 最长公共子序列 LCS问题是求两个字符串的最长公共子序列 \[ dp[i][j] = \left\{\begin{matrix} & max(d ...

随机推荐

  1. 【scala】 scala 映射和元组操作(四)

    1.映射  Map 定义 ,取值,遍历,排序 2. 元组 定义,取值,拉链操作 import scala.collection.mutable /** * 映射和元组 * * @author xwol ...

  2. C#调用Delphi的dll之详解

    C#调用Delphi接口方法,有两种解决办法: 一.将Delphi程序编译成一个COM组件,然后在C#里引用COM组件. 二.非托管调用Dephi的DLL文件. 这里我们主要讲解一下第二种方法,讲第二 ...

  3. winform 打开一个窗体,关闭一个窗体

    例如  我要打开一个窗体b,关闭一个窗体a a中的代码添加: private void pictureBox5_Click(object sender, EventArgs e) { W_MainFo ...

  4. getActionBar().setDisplayHomeAsUpEnabled(true)报空指针(已解决)

    今天捣鼓了一下午.getActionBar().setDisplayHomeAsUpEnabled(true)总是报空指针.在我的还有一个Android4.4.2的项目中就没有一点问题.我还以为是我自 ...

  5. Python中的and/or

    在Python中,可以通过and,or和not进行逻辑运算,下面就来看看and和or的简单介绍. 逻辑与-and 对于包含and运算的表达式,Python解释器将从左到右扫描,返回第一个为假的表达式值 ...

  6. Anaconda本地安装python库

    很多时候我们需要自己手动安装一些库,例如因为网络原因,或者下载源没有这个包. 以Windows环境为例,无论是pip安装还是anaconda安装,最终的包都是安装在,工作目录/Lib/site-pac ...

  7. linux下中文文件名乱码解决

    在windows上使用ftp上传文件到Linux上,中文名称在Linux系统中显示为乱码.虽然将Linux的env设置了LANG=en_US.UTF-8,并且本地的Shell客户端编码也设置成UTF- ...

  8. Synchronizing Threads and GUI in Delphi application

    Synchronizing Threads and GUI   See More About delphi multithreading tthread class user interface de ...

  9. Kafka producer拦截器(interceptor)

    Producer拦截器(interceptor)是个相当新的功能,它和consumer端interceptor是在Kafka 0.10版本被引入的,主要用于实现clients端的定制化控制逻辑. 对于 ...

  10. android新建的项目界面上没有显示怎么办?

    看log也没有说明具体情况? 一翻折腾在清单文件里加了权限就好了!!!