动态规划之最长公共上升子序列(LCIS)算法及优化
描述
给定两个整数序列,写一个程序求它们的最长上升公共子序列。
当以下条件满足的时候,我们将长度为N的序列S1 , S2 , . . . , SN 称为长度为M的序列A1 , A2 , . . . , AM 的上升子序列:存在 1 <= i1 < i2 < . . . < iN <= M ,使得对所有 1 <= j <=N,均有Sj = Aij,且对于所有的1 <= j < N,均有Sj < Sj+1。
输入
每个序列用两行表示,第一行是长度M(1 <= M <= 500),第二行是该序列的M个整数Ai (-231 <= Ai < 231 )
输出
在第一行,输出两个序列的最长上升公共子序列的长度L。在第二行,输出该子序列。如果有不止一个符合条件的子序列,则输出任何一个即可。
样例输入/输出
5
1 4 2 5 -12
4
-12 1 2 4
2
1 4
:这道题就是把之前学过的LCS和LIS合到一起了,所以参考之前LCS的状态转移方程,不难得到此题的状态转移方程:
① a[i] != b[j], dp[i][j] = dp[i-1][j]
② a[i] == b[j], dp[i][j] = max(dp[i-1][k]+1) (1 <= k <= j-1 && b[j] > b[k])
这里a[i]==b[i]的情况和LCS基本相同,只不过加入了k来确保在1到j-1区间能转移的数小于b[j](和LIS的原理一样),这里如果不理解就是LIS理解不到位,可以参考其他LIS的博客。a[i]!=b[i]的情况和LCS不同,因为 dp[i][j] 是以 b[j] 为结尾的LCIS,如果 dp[i][j] > 0 那么就说明 a[1]…a[i] 中必然有一个整数 a[k] 等于 b[j] ,因为 a[k] != a[i] ,那么 a[i] 对 dp[i][j] 没有贡献,于是我们不考虑它照样能得出 dp[i][j] 的最优值。所以在 a[i] != b[j] 的情况下必然有 dp[i][j] == dp[i-1][j] ,所以这也解释了为什么LCIS中没有LCS里dp[i][j]=dp[i][j-1]的情况。
根据状态转移方程及分析,不难写出最朴素的O(N * M^2)算法
代码:
int LCIS(int *a,int n,int *b,int m)
{
int ans=0;
int dp[505][505]={
0};
int tmp=0;
for (int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
dp[i+1][j+1]=dp[i][j+1];
if(a[i]==b[j])
{
tmp=0;
for(int k=0;k<j;k++)
{
if(b[j]>b[k]&&tmp<=dp[i][k+1]) tmp=dp[i][k+1];
}
dp[i+1][j+1]=tmp+1;
}
ans=ans>dp[i+1][j+1]?ans:dp[i+1