E - 最長公共子序列問題
阿新 • • 發佈:2020-10-20
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; }