程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 最長公共子序列,公共子序列

最長公共子序列,公共子序列

編輯:關於C語言

最長公共子序列,公共子序列


描述
  一個序列的子序列 (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 的最長公共子序列的長度。由最優子結構可得狀
態轉移方程如下:

      0                i = 0, j = 0

d[i][j] =  {  d[i − 1][j − 1] + 1        i, j > 0; xi = yi

      max {d[i][j − 1], d[i − 1][j]}    i, j > 0; xi ≠ yi

如果要打印出最長公共子序列,需要另設一個數組 p,p[i][j] 記錄 d[i][j] 是由哪個子問題得到的。

實現代碼

  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 }

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved