题意:
给你长度分别为n,m(1<=n,m<=500)的序列。要你求这两个序列的最长公共上升子序列。
思路:
最长公共子序列做过。最长上升子序列也做过。可是这题时最长公共上升子序列。。。解法肯定还是dp拉。
感觉这题的dp方程的思想非常不错,体现了一种加强约束的思想。dp[i][j]表示。处理完A序列的前i个,且上升序列以B序列的B[j]结尾的最长子序列。感觉这个把状态体现以什么结尾是非常不错的思想。然后转移显而易见了。
if(A[i]==B[j])
dp[i][j]=dp[i-1][k];//k是小于j且B[k]<B[j]
else
dp[i][j]=dp[i-1][j];
我们能够i,j循环这样就能够省掉找k的时间。复杂度O(n*m)
具体见代码:
#include<bits/stdc++.h> using namespace std; const int INF=0x3f3f3f3f; const int maxn=100010; typedef long long ll; int dp[550][550],A[550],B[550],path[550][550],n,m; bool print(int x) { if(!x) return false; if(print(path[n][x])) printf(" %d",B[x]); else printf("%d",B[x]); return true; } int main() { int i,j,tp,ans,pos; while(~scanf("%d",&n)) { for(i=1;i<=n;i++) scanf("%d",&A[i]); scanf("%d",&m); for(i=1;i<=m;i++) scanf("%d",&B[i]); memset(dp,0,sizeof dp); for(i=1;i<=n;i++) { tp=pos=0; for(j=1;j<=m;j++) { dp[i][j]=dp[i-1][j]; path[i][j]=path[i-1][j]; if(A[i]==B[j]&&tp+1>dp[i][j]) dp[i][j]=tp+1,path[i][j]=pos; if(B[j]<A[i]&&dp[i-1][j]>tp) tp=dp[i-1][j],pos=j; } } ans=1; for(i=1;i<=m;i++) if(dp[n][i]>dp[n][ans]) ans=i; printf("%d ",dp[n][ans]); if(dp[n][ans]) print(ans); printf(" "); } return 0; }
版权声明:本文博主原创文章。博客,未经同意不得转载。