Description
Input
Output
Sample Input
5 1 4 2 5 -12 4 -12 1 2 4
Sample Output
2 1 4
题意:求最长上升公共子序列(LCIS),并记录路径.
状态:dp[i][j]表示以s1串的前i个字符s2串的前j个字符且以s2[j]为结尾构成的LCIS的长度。
状态转移:当 s1[i-1]!=s2[j-1]时,按照lcs可知由2个状态转移过来,dp[i-1][j],dp[i][j-1],因为dp[i][j]是以s2[j]为结尾构成的LCIS的长度。所以s2[j-1]一定会包含在里面,所以舍去dp[i][j-1],只由dp[i-1][j] 转移过来。当s1[i-1]==s2[j-1],这时肯定要找前面s1[ii-1]==s2[jj-1]的最长且比s2[j-1]小的状态转移过来.
若s1[i-1]!=s2[j-1] 那么dp[i][j]=dp[i][j-1]
若s1[i-1]==s2[j-1] 那么dp[i][j]=MAX{dp[i-1][k]+1(0<k<j),s2[k-1]<s2[j-1]};
1 #include<stdio.h> 2 #include<string.h> 3 #define N 505 4 5 int i, j, n, m, len; 6 int s1[N], s2[N], rd[N][N], dp[N][N]; 7 8 void DP() 9 { 10 int mac = 0, ans = 0, I, J, lu[N], mx; 11 for(i = 1; i <= n; i++){ 12 mx = 0; 13 for(j = 1; j <= m; j++){ 14 int tem = dp[i][j] = dp[i-1][j]; 15 if(mx < tem && s1[i-1] > s2[j-1]){ 16 mx = tem; 17 mac = j; 18 } 19 if(s1[i-1] == s2[j-1]){ 20 dp[i][j] = mx + 1; 21 rd[i][j] = mac; 22 } 23 if(ans < dp[i][j]){ 24 ans = dp[i][j]; 25 I = i, J = j; 26 } 27 } 28 } 29 printf("%d\n", ans); 30 len = ans; 31 if(ans > 0) 32 lu[ans--] = J-1; 33 while(ans && I && J){ 34 if(rd[I][J] > 0){ 35 lu[ans--] = rd[I][J] - 1; 36 J = rd[I][J]; 37 } 38 I--; 39 } 40 for(i = 1; i <= len; i++) 41 printf("%d ",s2[lu[i]]); 42 printf("\n"); 43 } 44 45 int main() 46 { 47 scanf("%d", &n); 48 for(i = 0; i < n; i++) 49 scanf("%d", &s1[i]); 50 scanf("%d", &m); 51 for(i = 0; i < m; i++) 52 scanf("%d", &s2[i]); 53 DP(); 54 return 0; 55 }