LCS和LIS的结合,时间复杂度O(m*n),如果不要求路径输出 (如 Hdu 1426) 则空间复杂度O(n),若要求路径输出 (如 Poj 2127) 则空间复杂度O(n^2) 。
学习的时候最早读的是《动态规划中的提纯》,果断没看懂。。。。
参考了以下两篇博文后终于理解了算法的思想。
Hdu 1423 动态规划—最长公共上升子序列 - 诺小J - 博客园
http://www.cnblogs.com/nuoyan2010/archive/2012/10/17/2728289.html
【经典问题】最长公共上升子序列 | Clarkok
http://www.clarkok.com/blog/?p=353
贴上自己的代码:
Hdu 1423
#include <cstdio>
#include <iostream>
using namespace std;
int data1[505],data2[505];
int dp[505]; //dp[j]为序列2前j个元素与序列1构成的最长公共上升子序列的长度
int main ()
{
#ifdef ONLINE_JUDGE
#else
freopen("read.txt","r",stdin);
#endif
int T;
scanf("%d",&T);
while (T--)
{
int n,m,i;
scanf("%d",&n);
for (i=1;i<=n;i++)
scanf("%d",&data1[i]);
scanf("%d",&m);
for (i=1;i<=m;i++)
scanf("%d",&data2[i]);
memset(dp,0,sizeof(dp));
for (i=1;i<=n;i++)
for (int j=1,temp=0;j<=m;j++)
if (data2[j]<data1[i] && dp[j]>temp)
temp=dp[j];
else if (data1[i]==data2[j])
dp[j]=temp+1;
int ans=-1;
for (i=1;i<=m;i++)
if (dp[i]>ans)
ans=dp[i];
printf("%d\n",ans);
if (T)
printf("\n");
}
return 0;
}
Poj 2127
#include <cstdio>
#include <iostream>
#define max(x,y) ((x)>(y)?(x):(y))
using namespace std;
int data1[505],data2[505];
int dp[505],pre[505][505]; //dp[j]为序列2前j个元素与序列1构成的最长公共上升子序列的长度
int num[505];
int main ()
{
int n,m,i;
while (~scanf("%d",&n))
{
for (i=1;i<=n;i++)
scanf("%d",&data1[i]);
scanf("%d",&m);
for (i=1;i<=m;i++)
scanf("%d",&data2[i]);
memset(dp,0,sizeof(dp));
memset(pre,-1,sizeof(pre));
int x=0,y=0,ans=-1;
for (i=1;i<=n;i++)
{
int temp=0,last=0;
for (int j=1;j<=m;j++)
{
if (data2[j]<data1[i] && dp[j]>temp)
{
temp=dp[j];
last=j;
}
if (data1[i]==data2[j])
{
dp[j]=temp+1;
pre[i][j]=last;
}
if (dp[j]>ans)
{
ans=dp[j];
x=i; //最终结果x不一定等于n!
y=j;
}
}
}
printf("%d\n",ans);
int cas=ans;
for (i=ans;i>=1;i--)
{
num[i]=data2[y];
y=pre[x--][y];
while (data1[x]!=data2[y])
x--;
}
for (i=1;i<=cas;i++)
printf (i==cas?"%d\n":"%d ",num[i]);
}
return 0;
}