1. 程式人生 > 實用技巧 >E - 最長公共子序列問題

E - 最長公共子序列問題

Description

給定兩個序列 X={x1,x2,…,xm} 和 Y={y1,y2,…,yn},找出X和Y的最長公共子序列。

Input

輸入資料有多組,每組有兩行 ,每行為一個長度不超過500的字串(輸入全是大寫英文字母(A,Z)),表示序列X和Y。

Output

每組輸出一行,表示所求得的最長公共子序列的長度,若不存在公共子序列,則輸出0。

Sample

Input

ABCBDAB
BDCABA

Output

4

題解:

最長公共子序列(LCS)。
首先,從一個給定的串中刪去(不一定連續地刪去)0個或0個以上的字元,剩下地字元按原來順序組成的串。例如:“ ”,“a”,“xb”,“aaa”,“bbb”,“xabb”,“xaaabbb”都是串“xaaabbb”的子序列。(例子中的串不包含引號。)
若s1[i] = s2[j]時,那麼當前字母一定是某個公共子序列的尾字母,那麼只要尋找s1與S2去掉當前字母的公共最長公共子序列+1(LCS(i-1, j-1)+1)就是當前兩個字串的最長公共子序列。
若s1[i] ≠ s2[j]時,那麼當前最長公共子序列為max(LCS(i-1,j),LCS(i,j-1))。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define maxn 505
using namespace std;

/**
*s1 s2分別儲存兩個字串。
*/
char s1[maxn],s2[maxn];
/**
*dp當前最大公共子序列
*/
int dp[maxn][maxn];

/**
*LCS()求最長公共子序列的函式
*i s1當前的遊標。
*j s2當前的遊標。
*/
int lcs(int i,int j){
    if(dp[i][j] != -1)
        return dp[i][j];
    //若有一方為0既當前有一個字串長度為0.則公共子序列也為0;
    if(i==0||j==0){
        dp[i][j] = 0;
    }
    //若s1[i] = s2[j]時,那麼當前字母一定是某個公共子序列的尾字母,
    //那麼只要尋找(LCS(i-1, j-1)+1)就是當前兩個字串的最長公共子序列。
    else if(s1[i - 1] == s2[j - 1]){
            dp[i][j] = lcs(i - 1, j - 1) + 1;
        }
    //若s1[i] ≠ s2[j]時,那麼當前最長公共子序列為
    //max(LCS(i-1,j),LCS(i,j-1))。
    else{
            dp[i][j] = max(lcs(i - 1, j), lcs(i, j - 1));
        }
    return dp[i][j];
}

int main()
{
    /**
    *l1字串1的長度
    *l2字串2的長度
    */
    int l1,l2;
    while(scanf("%s%s",s1,s2)!=EOF){
        memset(dp,-1,sizeof(dp));
        l1 = strlen(s1);
        l2 = strlen(s2);
        printf("%d\n",lcs(l1,l2));
    }
    return 0;
}