描述
一个序列的子序列 (subsequence) 是指在该序列中删去若干(能够为 0 个)元素后获得的序列。准确的说,若给定序列 X = (x1 , x2 , · · · , xm ),则另外一个序列 Z = (z1 , z2 , · · · , zk ),是 X 的子序列是指存在一个严格递增下标序列 (i1 , i2 , · · · , ik ) 使得对于全部 j = 1, 2, · · · , k有 zj = xij 。例如,序列 Z = (B, C, D, B) 是序列 X = (A, B, C, B, D, A, B) 的子序列,相应的递增下标序列为 (1, 2, 4, 6)。给定两个序列 X 和 Y,求 X 和 Y 的最长公共子序列 (longest common subsequence)。数组
输入
输入包括多组测试数据,每组数据占一行,包含两个字符串(字符串长度不超过 200),表明两个序列。两个字符串之间由若干个空格隔开。测试
输出
对每组测试数据,输出最大公共子序列的长度,每组一行。
样例输入
abcfbc abfcab
programming contest
abcd mnp
样例输出
4
2
0
分析
最长公共子序列问题具备最优子结构性质。设序列 X = (x1 , x2 , · · · , xm ) 和 Y = (y1 , y2 , · · · , yn ) 的最长公共子序列为 Z = (z1 , z2 , · · · , zk ),则
• 若 xm = yn ,则 zk = xm = yn ,且 Zk−1 是 Xm−1 和 Yn−1 的最长公共子序列。
• 若 xm ≠ yn 且 zk ≠ xm ,则 Z 是 Xm−1 和 Y 的最长公共子序列。
• 若 xm ≠ yn 且 zk ≠ yn ,则 Z 是 X 和 Yn−1 的最长公共子序列。
其中,Xm−1 = (x1 , x2 , · · · , xm−1 ), Yn−1 = (y1 , y2 , · · · , yn−1 ), Zk−1 = (z1 , z2 , · · · , zk−1 )。
设状态为 d[i][j],表示序列 Xi 和 Yj 的最长公共子序列的长度。由最优子结构可得状
态转移方程以下:spa
0 i = 0, j = 0code
d[i][j] = { d[i − 1][j − 1] + 1 i, j > 0; xi = yiblog
max {d[i][j − 1], d[i − 1][j]} i, j > 0; xi ≠ yi
若是要打印出最长公共子序列,须要另设一个数组 p,p[i][j] 记录 d[i][j] 是由哪一个子问题获得的。字符串
实现代码string
1 #include <stdio.h> 2 #include <string.h> 3 #define MAX 201 4 /* 字符串最大长度为 200 */ 5 6 int d[MAX][MAX]; /* d[i][j] 表示序列 Xi 和 Yj 的最长公共子序列的长度 */ 7 char x[MAX], y[MAX]; /* 字符串末尾有个'0' */ 8 9 void lcs(const char *x, const int m, const char *y, const int n) 10 { 11 int i, j; 12 for (i = 0; i <= m; i++) 13 d[i][0] = 0; 14 for (j = 0; j <= n; j++) 15 d[0][j] = 0; 16 17 /* 边界初始化 */ 18 for (i = 1; i <= m; i++) 19 { 20 for (j = 1; j <= n; j++) 21 { 22 if (x[i-1] == y[j-1]) 23 { 24 d[i][j] = d[i-1][j-1] + 1; 25 } else { 26 d[i][j] = d[i-1][j] > d[i][j-1] ? d[i-1][j] : d[i][j-1]; 27 } 28 } 29 } 30 } 31 32 void lcs_extend(const char *x, const int m, const char *y, const int n); 33 void lcs_print(const char *x, const int m, const char *y, const int n); 34 35 int main() 36 { 37 while (scanf ("%s%s", x, y) != EOF) 38 { 39 const int lx = strlen(x); 40 const int ly = strlen(y); 41 lcs(x, lx, y, ly); 42 printf ("%d\n", d[lx][ly]); 43 } 44 return 0; 45 } 46 47 int p[MAX][MAX]; /* p[i][j] 记录 d[i][j] 是由哪一个子问题获得的 */ 48 void lcs_extend(const char *x, const int m, const char *y, const int n) 49 { 50 int i, j; 51 memset(p, 0, sizeof(p)); 52 for (i = 0; i <= m; i++) 53 d[i][0] = 0; 54 for (j = 0; j <= n; j++) 55 d[0][j] = 0; 56 57 /* 边界初始化 */ 58 for (i = 1; i <= m; i++) 59 { 60 for (j = 1; j <= n; j++) 61 { 62 if (x[i-1] == y[j-1]) 63 { 64 d[i][j] = d[i-1][j-1] + 1; 65 p[i][j] = 1; 66 } 67 else 68 { 69 if (d[i-1][j] >= d[i][j-1]) 70 { 71 d[i][j] = d[i-1][j]; 72 p[i][j] = 2; 73 } 74 else 75 { 76 d[i][j] = d[i][j-1]; 77 p[i][j] = 3; 78 } 79 } 80 } 81 } 82 } 83 84 void lcs_print(const char *x, const int m, const char *y, const int n) 85 { 86 if (m == 0 || n == 0) 87 return; 88 if (p[m][n] == 1) 89 { 90 lcs_print(x, m - 1, y, n - 1); 91 printf("%c", x[m - 1]); 92 } 93 else if (p[m][n] == 2) 94 { 95 lcs_print(x, m - 1, y, n); 96 } 97 else 98 { 99 lcs_print(x, m, y, n - 1); 100 } 101 }