Description
给定两个数列,求最长公共上升子序列,并输出其中一种方案。
Input&Output
Input
第一行一个整数n(0<n<=500),数列a的长度。
第二行n个空格隔开的整数,数列a的元素。
第三行一个整数m,数据范围同n,数列b的长度。
第四行m个空格隔开的整数,意义同第二行。
Output
第一行一个整数k,LCIS的长度。
第二行k个空格隔开的整数,其中一种方案。
Solution
对于这类问题我们通常有两种转移方式,一种是以i结尾的数列,另一种是前i个数中选择一些组成的数列。
此题中我们选用a数组前i个元素,b数组以j结尾来转移,空间为O(n^2),时间为O(n^3).其实求上升的时间可以进一步优化到O(n^2logn),但本题数据不需要。
再来说方案:维护一个LICS[i][],代表以j结尾的LICS方案,每更新一次答案,则将方案也迁移过来。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 505
using namespace std;
int n,m,a[maxn],b[maxn],f[maxn][maxn],lics[maxn][maxn];
int ans,pos;
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;++i)cin>>a[i];
cin>>m;
for(int i=1;i<=m;++i)cin>>b[i];
f[0][0]=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
if(a[i]!=b[j])f[i][j]=f[i-1][j];
else {
f[i][j]=1;
for(int k=1;k<j;++k){
if(b[k]<b[j])
{
if(f[i-1][k]+1>f[i][j]){
f[i][j]=f[i-1][k]+1;
for(int p=1;p<=f[i-1][k];++p)lics[j][p]=lics[k][p];
}
}
}
lics[j][f[i][j]]=b[j];
}
}
for(int i=1;i<=m;++i){
if(f[n][i]>ans)ans=f[n][i],pos=i;
}
printf("%d\n",ans);
for(int i=1;i<=f[n][pos];++i)printf("%d ",lics[pos][i]);
return 0;
}
原文地址:https://www.cnblogs.com/nishikino-curtis/p/8693731.html
时间: 2024-12-29 06:57:25