問題描述
某個序列的子序列是從最初序列通過去除某些元素但不破壞餘下元素的相對位置而形成的新序列。
給定兩個序列X和Y,如果Z既是X的一個子序列又是Y的一個子序列,則稱Z是X,Y的公用子序列。
給定兩個序列X={x1,x2...,xm}和Y={y1,y2...yn},找出Z={z0,z1,…,zk}為它們的最長公用子序列.
最優子結構
設X={x1,x2...,xm}和Y={y1,y2...yn}為兩個序列,Z={z0,z1,…,zk}為任意一個LCS。
1)如果xm=ym,那麼zk=xm=ym,且Zk-1為Xm-1和Yn-1的一個LCS。
2)如果xm!=ym&&zk!=xm,那麼Z是Xm-1和Y的一個LCS。
3)如果xm!=ym&&zk!=yn,那麼Z是X和Yn-1的一個LCS。
狀態轉移方程
c[i,j]為序列Xi和Yi的一個LCS的長度。
代碼實現
//LCS#include<iostream>#include<string>using namespace std;void LCS_Length(string x,string y,int (*c)[100],int (*b)[100]){int m,n;m=x.length();n=x.length();int i,j;//如果i或j等於0則c[i][j]=0;for(i=1;i<=m;i++){c[i][0]=0;}for(i=1;i<=n;i++){c[0][i]=0;}//遍曆兩個字串,依次標記c[i][j],c[i][j]標記了從x的開始到第i個元素與從//y開始到第j個元素中LCS的長度//數組b用來標記最長公用子串所要走的路線,該路線為兩個字串組成的矩陣中的對應的字母for(i=1;i<=m;i++){for(j=1;j<=n;j++){if(x[i-1]==y[j-1]){c[i][j]=c[i-1][j-1]+1;//代替箭頭指向左上b[i][j]=1;}else{if(c[i][j-1]>=c[i-1][j]){c[i][j]=c[i][j-1];//代替箭頭指左b[i][j]=2;}else{c[i][j]=c[i-1][j];//代替箭頭指向上b[i][j]=3;}}}}}void PrintAnswer(string x,int(*b)[100],int i,int j){if(i==0||j==0){return ;}else{if(b[i][j]==1){PrintAnswer(x,b,i-1,j-1);cout<<x[i-1]<<" ";}else if(b[i][j]==2){PrintAnswer(x,b,i,j-1);}else{PrintAnswer(x,b,i-1,j);}}}int main(){string x="abcbda";string y="bdcaba";int c[100][100]={0};int b[100][100]={0};LCS_Length(x,y,c,b);cout<<"the LCS is: "<<c[x.length()][y.length()]<<endl;PrintAnswer(x,b,x.length(),y.length());return 0;}
參考:最長公用子串LCS代碼實現-http://blog.csdn.net/liuzhanchen1987/article/details/7851413