最长公共上升子序列慕名而知是两个字符串a,b的最长公共递增序列,不一定非得是连续的。刚开始看到的时候想的是先用求最长公共子序列,然后再从其中找到最长递增子序列,可是仔细想一想觉得这样有点不妥,然后从网上看了一些大神的理解,觉得恍然大悟。
定义dp[i][j]表示字符串a前i个和字符串b的前j个且以b[j]结尾构成的最长公共上升子序列的长度,定义一个max用来保存最大的长度。用两个循环,外层循环控制字符串a,内层循环控制字符串b。如果a[i]不等于b[j],则dp[i][j]=dp[i-1][j];如果a[i]大于b[j]而且max<dp[i-1][j],则max=dp[i-1][j];如果a[i]等于b[j],则dp[i][j]=max+1。最后的答案在dp[n][1~m]中最大的。(注意,这种情况是字符串都是从下标为1开始存的)
下面是例题: 杭电1423
Greatest Common Increasing Subsequence
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3482 Accepted Submission(s):
1098
Problem Description
This is a problem from ZOJ 2432.To make it easyer,you
just need output the length of the subsequence.
Input
Each sequence is described with M - its length (1 <=
M <= 500) and M integer numbers Ai (-2^31 <= Ai < 2^31) - the sequence
itself.
Output
output print L - the length of the greatest common
increasing subsequence of both sequences.
Sample Input
1
5
1 4 2 5 -12
4
-12 1 2 4
Sample Output
2
代码如下:
1 #include <iostream> 2 using namespace std; 3 int t,n,m; 4 int a[503],b[503]; 5 int dp[503][503]; 6 7 int LCIS() 8 { 9 int i,j; 10 int max; 11 for(i=1;i<=n;i++) 12 { 13 max = 0; 14 for(j=1;j<=m;j++) 15 { 16 dp[i][j] = dp[i-1][j]; 17 if (a[i]>b[j] && max<dp[i-1][j]) 18 max = dp[i-1][j]; 19 if(a[i] == b[j]) 20 dp[i][j] = max + 1; 21 } 22 } 23 max = 0; 24 for(i=1;i<=m;i++) 25 if(max<dp[n][i]) 26 max = dp[n][i]; 27 return max; 28 } 29 30 int main() 31 { 32 int i,j; 33 cin>>t; 34 while(t--) 35 { 36 cin>>n; 37 for(i=1;i<=n;i++) 38 cin>>a[i]; 39 cin>>m; 40 for(j=1;j<=m;j++) 41 cin>>b[j]; 42 memset(dp,0,sizeof(dp)); 43 cout<<LCIS()<<endl; 44 if (t) 45 cout<<endl; 46 } 47 }
其实还有一种更牛的方法是采用一维数组,但是时间还是n^2。当i循环到k的时候,原来dp[i]表示原来的dp[k][j],因为当a[i]!=b[j]的时候dp[i]的值是不变的,沿用过去的值就行了,只有当a[i]==b[j]的时候才需要更新dp[i]的值。
代码如下:
1 #include <iostream> 2 using namespace std; 3 int t,n,m; 4 int a[503],b[503]; 5 int dp[503]; 6 7 int LCIS() 8 { 9 int i,j; 10 int max; 11 for(i=1;i<=n;i++) 12 { 13 max = 0; 14 for(j=1;j<=m;j++) 15 { 16 if (a[i]>b[j] && max<dp[j]) 17 max = dp[j]; 18 if(a[i] == b[j]) 19 dp[j] = max + 1; 20 } 21 } 22 max = 0; 23 for(i=1;i<=m;i++) 24 if(max<dp[i]) 25 max = dp[i]; 26 return max; 27 } 28 29 int main() 30 { 31 int i,j; 32 cin>>t; 33 while(t--) 34 { 35 cin>>n; 36 for(i=1;i<=n;i++) 37 cin>>a[i]; 38 cin>>m; 39 for(j=1;j<=m;j++) 40 cin>>b[j]; 41 memset(dp,0,sizeof(dp)); 42 cout<<LCIS()<<endl; 43 if (t) 44 cout<<endl; 45 } 46 }