动态规划-最长公共上升子序列
有关概念:
最长公共上升子序列(LCIS),两个或者两个以上序列的所有共同上升子序列最长的一个(又好像和没解释没什么区别)
思路:
对于两个序列a,b
f[i][j]表示a序列中1..i的部分和b序列中1...j的部分的LCIS
那么易得,对于f[i][j]:
(1)如果ai!=bj,则直接将f[i-1][j]作为其前驱,因为在ai之前必有一个数ak==bj,即使ai-1!=bj,也可以由f[k][j]一步步将值继承下来,这与LCS的想法相似;
(2)否则,则从f[i-1][1...j]中挑选最大值,作为其前驱,继承其值并++;
最后输出f[lena][lenb]即可……
然而,这样是o(n3)的算法,优化的方法是在第二层j的循环时记录一个max值,只要bj<ai时(满足“上升”),就更新其值,在之后ai==bj时,直接取max更新f[i][j]即可
当然,可以在更新f[i][j]的时候附带更新数组记录其前驱的位置,以便最后输出
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 #define MAXN 5 int lena,lenb,a[MAXN],b[MAXN],ans1,ans2[MAXN]; 6 struct node 7 { 8 int x,nextx,nexty; 9 }f[MAXN][MAXN]; 10 int main() 11 { 12 scanf("%d",&lena);for(int i=1;i<=lena;++i)scanf("%d",&a[i]); 13 scanf("%d",&lenb);for(int i=1;i<=lenb;++i)scanf("%d",&b[i]); 14 swap(a,b); 15 int t=lena;lena=lenb;lenb=t; 16 for(int i=1;i<=lena;++i) 17 { 18 node max=(node){0,0,0}; 19 for(int j=1;j<=lenb;++j) 20 { 21 f[i][j]=(node){f[i-1][j].x,i-1,j}; 22 if(b[j]<a[i]&&f[i-1][j].x>max.x)max=(node){f[i-1][j].x,i-1,j}; 23 else if(a[i]==b[j])f[i][j]=(node){max.x+1,max.nextx,max.nexty}; 24 } 25 } 26 int k1=0,k2; 27 for(int i=1;i<=lenb;++i) 28 { 29 if(f[lena][i].x>k1) 30 { 31 k1=f[lena][i].x; 32 k2=i; 33 } 34 } 35 printf("%d\n",k1); 36 int x=lena,y=k2; 37 while(x&&y) 38 { 39 node temp=f[x][y]; 40 if(f[temp.nextx][temp.nexty].x==temp.x-1)ans2[++ans1]=a[x]; 41 x=temp.nextx;y=temp.nexty; 42 } 43 for(int i=ans1;i>=1;--i)printf("%d ",ans2[i]); 44 }