做了一段时间的线性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. MySQL数据库辅助类

    /** *创建人:CalvinR *说明:数据库辅助类 **/ namespace Study.Utilities.MySql_Connect { /// <summary> /// My ...

  2. Java终止循环体

    编写程序,是先创建一个字符串数组,在使用foreach语句遍历时,如果发现数组中包含字符串“老鹰”则立刻中断循环.再创建一个整数类型的二维数组,使用双层foreach语句循环遍历,当发现第一个小于60 ...

  3. Lab6: Paxos

    Introduction In labs 6 and 7, you will replicate the lock service using the replicated state machine ...

  4. java.security.NoSuchAlgorithmException: SHA1PRNG SecureRandom not available

    好久没有使用MyEclipse10了,今天打开看了以前大学的项目,在Tomcat7中发布启动,我嚓嘞,报错: SEVERE: Exception initializing random number ...

  5. Python中执行外部命令

    有很多需求需要在Python中执行shell命令.启动子进程,并捕获命令的输出和退出状态码,类似于Java中的Runtime类库. subprocess模块的使用: Python使用最广泛的是标准库的 ...

  6. U3D 游戏引擎之游戏架构脚本该如何来写

    这篇文章MOMO主要想大家说明一下我在Unity3D游戏开发中是如何写游戏脚本的,对于Unity3D这套游戏引擎来说入门极快,可是要想做好却非常的难.这篇文章的目的是让哪些已经上手Unity3D游戏引 ...

  7. Kafka manager安装 (支持0.10以后版本consumer)

    下载地址:  https://pan.baidu.com/s/1jIE3YL4 步骤: 1. 解压kafka-manager-1.3.2.1.zip 2. cd kafka-manager-1.3.2 ...

  8. Swift - 可选类型详解

    可选类型详解 直接上代码解释 // 类中所有的属性在对象初始化时,必须有初始化值 class Person : NSObject { var name : String? var view : UIV ...

  9. WP8.1学习系列(第二章)——Toast通知

    Toast 通知概述(Windows 运行时应用) 你的应用要想通过 Toast 通知通信,必须在应用的清单文件中声明它支持 Toast.Toast 通知可包含文本,并且 Windows 上的 Toa ...

  10. Delphi应用程序的调试(六)步进式代码调试

    步进式代码调试(Stepping Through Your Code) 步进式代码调试是最基本的调试操作之一,但仍要在此讲述.人们常常容易犯只见树木不见森林的错误.经常复习基本的知识有助于读者了解以前 ...