题目:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=107450#problem/C
题意:输入两个字符串,找一个最短的串,使得输入的两个串均是他的子序列,统计长度最短的串的个数;
分析:最短串的长度就等于a串长度 + b串长度 - LCS( a, b )
c[i][j]表示a串前i个元素和b串前j个元素所能得到的方案数。l[i][j]表示LCS的长度
若a[i]=b[j],那么c[i][j]=c[i-1][j-1],即a串前i-1个元素和b串前j-1个元素得到的组合串的末尾加上一个相同的元素a[i],那么得到的新的组合串的个数还是和之前的组合串的个数一样
若a[i]!=b[j], l[i][j]=max { l[i-1][j] , l[i][j-1]}
若l[i-1][j]>l[i][j-1],那说明从l[i-1][j]这种状态开始构建才能得到最终的LCS同时最终的组合串才不能漏掉共有的元素,所以c[i][i]=c[i-1][j],即在a串i-1个元素和b串j个元素组成的组合串的后面加上a[i],那么得到的新的组合串的个数和之前的组合串的个数是相同的
若l[i][j-1]>l[i-1][j],道理和上面是一样的,所以c[i][j]=c[i][j-1],相当于在之前的组合串后面加上元素b[j],得到新的组合串的个数不变
若l[i][j-1]=l[i-1][j],说明从两种状态都是能得到最终的LCS并且最终的组合串不会漏掉任何相同的公共元素,所以c[i][j]=c[i-1][j]+c[i][j-1] , 即用a串的i-1个元素和b串的j个元素组成的组合串的最后加上a[i]得到新的组合串和之前的组合串个数相同,另外用a串的i个元素和b串的的j-1个元素组成的组合串的最后加上b[j]得到新的组合串和之前的组合串个数相同,那么就是两者之和
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <cstdio> 5 using namespace std; 6 const int Max = 50; 7 char a[Max],b[Max]; 8 int c[Max][Max],l[Max][Max],B[Max][Max]; 9 /* 10 void print(int i, int j) 11 { 12 if(i == 0 && j == 0) 13 return; 14 if(i == 0) 15 { 16 for(int k = 1; k <= j; k++) 17 printf("%c", b[k]); 18 return; 19 } 20 if (j == 0) 21 { 22 for(int k = 1; k <= i; k++) 23 printf("%c", a[k]); 24 return; 25 } 26 if(B[i][j] == 0) 27 { 28 print(i - 1, j - 1); 29 printf("%c", a[i]); 30 } 31 else if(B[i][j] == 1) 32 { 33 print(i - 1, j); 34 printf("%c", a[i]); 35 } 36 else 37 { 38 print(i, j - 1); 39 printf("%c", b[j]); 40 } 41 } 42 */ 43 int main() 44 { 45 int test; 46 scanf("%d", &test); 47 getchar(); 48 for(int t = 1; t <= test; t++) 49 { 50 gets(a + 1); 51 gets(b + 1); 52 int lena = strlen(a + 1); 53 int lenb = strlen(b + 1); 54 for(int i = 0; i <= lena; i++) 55 { 56 for(int j = 0; j <= lenb; j++) 57 c[i][j] = 1; 58 } 59 memset(l, 0, sizeof(l)); 60 memset(B, 0, sizeof(b)); 61 for(int i = 1; i <= lena; i++) 62 { 63 for(int j = 1; j <= lenb; j++) 64 { 65 if(a[i] == b[j]) 66 { 67 l[i][j] = l[i - 1][j - 1] + 1; 68 c[i][j] = c[i - 1][j - 1]; 69 B[i][j] = 0; 70 } 71 else 72 { 73 l[i][j] = max(l[i - 1][j], l[i][j - 1]); 74 if(l[i - 1][j] > l[i][j - 1]) 75 { 76 c[i][j] = c[i - 1][j]; 77 B[i][j] = 1; 78 } 79 else if(l[i - 1][j] < l[i][j - 1]) 80 { 81 c[i][j] = c[i][j - 1]; 82 B[i][j] = -1; 83 } 84 else 85 { 86 c[i][j] = c[i - 1][j] + c[i][j - 1]; 87 } 88 } 89 } 90 } 91 printf("Case #%d: %d %d ", t, lena + lenb - l[lena][lenb], c[lena][lenb]); 92 93 } 94 return 0; 95 }