题意和解析见代码最后部分
#include<iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[505],b[505];
int dp[505][505];
int n,m;
int path[505][505];
int I,J,ans,res[505];
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i = 0 ; i < n ; i++)
{
scanf("%d",&a[i]);
}
scanf("%d",&m);
for(int i = 0 ; i < m ; i++)
{
scanf("%d",&b[i]);
}
for(int i = 0 ; i <= n ; i++)
{
dp[i][0] = 0 ;
}
for(int j = 0 ; j <= m ; j++)
{
dp[0][j] = 0 ; //字符都是计算的从1开始的,所以这些都是0,初始化
}
int ans = 0 ;
memset(path,-1,sizeof(path));
for(int i = 1 ; i <= n ; i++)
{
for(int j = 1 ; j <= m ; j++)
{
dp[i][j]=dp[i-1][j];
if(a[i-1]==b[j-1])
{
int maxnn=0;
for(int k=1;k<j;k++)
{
if(b[k-1]<b[j-1]&&dp[i][maxnn]<dp[i][k])
{
maxnn=k;
}
}
if(dp[i][maxnn]+1 > dp[i][j])
{
dp[i][j]=dp[i][maxnn]+1;
path[i][j]=maxnn;
if(dp[i][j] > ans)
{
ans=dp[i][j];
I=i;
J=j;
}
}
}
}
}
printf("%d\n",ans);
int k=ans;
while(ans)
{
if(path[I][J]>=0)
{
res[ans--]=b[J-1];
J=path[I][J];
}
I--;
}
for(int i = 1 ; i <= k ; i++)
printf("%d ",res[i]);
printf("\n");
}
return 0;
}
/*
Auther:LIUYAN
2015.12.01
POJ 2027 LCIS(最长上升公共子序列)
并且将选择的数字输出
思路:
假如将dp[i][j]定义为第一个字符串的前i个字符和第二个字符串的前j个字符
中的最长上升子序列的话,递推结果为:
if(a[n]==b[m]) dp[n][m] = max(dp[i][j]) + 1 ;(i<n,j<m, a[i]<=a[n],b[j]<=b[m])
else dp[n][m] = max(dp[i][j]) ;(i<n,j<m)
这样的结果是,时间复杂度为O(n^4)
我们换一种思路,我们发现每次dp[i][j]的长度会增加1的情况都是a[i]==b[j],
所以我们定义dp[i][j]为以第一个字符的第i个字符结尾和第二个字符的前j个字符
组成的最长上升子序列,这样的递推结果为:
if(a[n]==b[m]) dp[n][m] = max(dp[n-1][j])+1 ;(j<m, b[j]<=b[m])
else dp[n][m] = dp[n-1][m] ;
此时时间复杂度为O(n^3)
5
1 4 2 5 -12
4
-12 1 2 4
*/