【poj 2127】Greatest Common Increasing Subsequence 最长公共上升子序列lics+路径打印

来源:互联网 发布:新媒体与网络传播 编辑:程序博客网 时间:2024/06/05 18:43

题意:给你两个数列,叫你求他们的最长公共子序列,并且打印路径

对于最长子序列的n*m算法,网上多的是,可以具体去找一下,这里只做一个小结:

定义f[i][j]表示对于a数组的第i个为止(包括前面的),然后b数组以j结尾(必须是j),的最长公共上升子序列,很容易想到n3复杂的的算法

if( a[ i ] != b[ j ] ) f[ i ][ j ] = f[ i-1 ] [ j ](参考lcs算法)

if( a[ i ] ==b [ j ]) f[ i ][ j ] = max( f[ i-1 ][ k ]+1) k<j

这里的优化就在于每一次都要去求一个max而事实是在遍历这个数字之前,所有的f[i-1][k]的情况都会访问一次,就会有很多重复,所以每一次定义一个之前最大值,用的时候就可以直接更新了,那么接下来的问题就是什么时候更新这个最大值呢?有一个事实是,只有当a[ i ] == b [ j ]的时候我们才会用到这个最大值,所以呢,每次只要 a[ i ]> b[ j ]就更新,保证后面找到的b[ j ]一定比前面大


最后也是最关键的就是打印路径的问题,之前也做过几个类似的打印路径的题,基本上是dp开几维这就几维,但是一开始只想用一维的,而且样例也是没有错的,过了很多组,但是忽略了一个事实就是后面的数字会更改前继。比如这个数据:

63 6 9 12 4 653 4 6 9 12
就会错,不懂就自己慢慢调试就知道了

正确代码:

#include<cstdio>#include<cstring>#include<iostream>#define clear(x) memset(x,0,sizeof(x))#define maxn 521using namespace std;int n,m,path[maxn][maxn],f[maxn][maxn],a[maxn],b[maxn],ans,q[maxn];int main(){while(~scanf("%d",&n)){ans=0;int ai,aj;clear(f);clear(path);clear(q);for(int i=1;i<=n;i++)scanf("%d",a+i);scanf("%d",&m);for(int i=1;i<=m;i++)scanf("%d",b+i);for(int i=1;i<=n;i++){int Max=0,mj=0;for(int j=1;j<=m;j++){f[i][j]=f[i-1][j];path[i][j]=-1;if(a[i]>b[j]&&f[i][j]>Max){Max=f[i][j],mj=j;}if(a[i]==b[j]){f[i][j]=Max+1;path[i][j]=mj;}if(f[i][j]>ans){ans=f[i][j];ai=i,aj=j;}}}printf("%d\n",ans);int tem=ans;while(tem){if(path[ai][aj]!=-1){q[tem--]=b[aj];aj=path[ai][aj];}ai--;}for(int i=1;i<=ans;i++)printf("%d%c",q[i],i==ans?'\n':' ');}return 0;}

bug代码:

#include<cstdio>#include<cstring>#include<iostream>#include<stack>#define maxn 1020using namespace std;int a[maxn],b[maxn],f[maxn][maxn],n,m,dp[maxn];stack<int>s;void front(){memset(a,0,sizeof(a));memset(b,0,sizeof(b));memset(f,0,sizeof(f));while(!s.empty())s.pop();}int main(){while(scanf("%d",&n)!=EOF){front();for(int i=1;i<=n;i++)scanf("%d",a+i);scanf("%d",&m);for(int i=1;i<=m;i++)scanf("%d",b+i);for(int i=1;i<=n;i++){int Max=0;for(int j=1;j<=m;j++){f[i][j]=f[i-1][j];if(a[i]>b[j])Max=max(Max,f[i-1][j]);if(a[i]==b[j])f[i][j]=max(f[i][j],Max+1);}}int ans=0,j,last=1e9;for(int i=m;i>=1;i--){ans=max(ans,f[n][i]);}int x=ans;for(int i=m;i>=1;i--){if(f[n][i]==x&&b[i]<last){s.push(b[i]);x--;last=b[i];}}printf("%d\n",ans);if(ans==0)printf("\n");elsewhile(!s.empty()){printf("%d ",s.top());s.pop();}printf("\n");}return 0;}/*4 1 7 6 84 1 7 8 6*/


0 0