HLBU 2029: 最长公共子序列
http://42.96.145.57/JudgeOnline/problem.php?id=2029
题目描述
字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一个严格递增下标序列<i0,i1,…,ik-1>,使得对所有的j=0,1,…,k-1,有xij=yj。例如,X=“ABCBDAB”,Y=“BCDB”是X的一个子序列。
输入
两个字符串
输出
最长公共子序列的长度
最长公共子序列
样例输入
ABCBDAB BDCABA
样例输出
4 BCBA
输出那一快花了挺长时间,这道题有好多细节需要想清楚
该题动态规划公式:
做这题参考了这篇文章,http://www.cnblogs.com/huangxincheng/archive/2012/11/11/2764625.html,写的不错,还有图解,不过代码不是C或者C++。
1 #include <iostream> 2 #include <stdio.h> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 #define maxSize 1000 7 char str1[maxSize], str2[maxSize]; 8 int mem[maxSize][maxSize]; //用于输出最长子序列的回溯矩阵 9 10 //回溯输出最长子序列 11 void print(int m[][maxSize], char *str1, int i, int j) 12 { 13 if(i==0||j==0) return; 14 if(m[i][j]==0) 15 { 16 print(m, str1, i-1, j-1); 17 cout<<str1[i-1]; //输出放在print之后正序输出,放在print之前逆序输出 18 } 19 else if(m[i][j]==-1) 20 { 21 print(m, str1, i, j-1); 22 } 23 else 24 { 25 print(m, str1, i-1, j); 26 } 27 } 28 29 int main() 30 { 31 while(cin>>str1>>str2) 32 { 33 int len1 = strlen(str1); 34 int len2 = strlen(str2); 35 int dp[len1+1][len2+1]; 36 memset(dp, 0, sizeof(dp)); 37 memset(mem, 0, sizeof(mem)); 38 for(int i=1; i<=len1; i++) 39 { 40 for(int j=1; j<=len2 ;j++) 41 { 42 if(str1[i-1]==str2[j-1]) 43 { 44 dp[i][j] = dp[i-1][j-1]+1; 45 mem[i][j]=0;//向左上走 46 } 47 //如果有多个长度相同的最长子序列,优先向上走,则得到字符串1其中的第一个,否则得到字符串1中的走后一个 48 else if(dp[i-1][j] >= dp[i][j-1] ) 49 { 50 dp[i][j] = dp[i-1][j]; 51 mem[i][j] = 1;//向上走 52 } 53 else 54 { 55 dp[i][j] = dp[i][j-1]; 56 mem[i][j] = -1; //向左走 57 } 58 } 59 } 60 61 /********打印回溯矩阵****** 62 for(int i=0; i<=len1; i++) 63 { 64 for(int j=0; j<=len2 ;j++) 65 { 66 cout<<mem[i][j]<<" "; 67 } 68 cout<<endl; 69 } 70 *************************/ 71 72 cout<<dp[len1][len2]<<endl; 73 print(mem, str1, len1, len2); 74 cout<<endl; 75 } 76 return 0; 77 }