算法:动态规划——最长公共子序列(LCS)

来源:互联网 发布:windows xp logo 编辑:程序博客网 时间:2024/05/31 18:38
转自:http://blog.163.com/zhaohai_1988/blog/static/2095100852012792947765    
    最长公共子序列的意思就是寻找两个给定字符串的的子序列,该子序列在两个字符串中以相同的次序出现,但是不一定是连续的。(连续的那是子串)
    例如序列X=ABCBDAB,Y=BDCABA。序列BCA是X和Y的一个公共子序列,但是不是X和Y的最长公共子序列,子序列BCBA是X和Y的一个LCS,序列BDAB也是。
   思路:   
    最长公共子序列是动态规划(DP)的典型例子。

    设X=<x1,x2,…,xm>和Y=<y1,y2,…,yn>为两个字符串,LCS(X,Y)表示X和Y的一个最长公共子序列,可以看出

  1. 如果xm=yn,则LCS ( X,Y ) = xm + LCS ( Xm-1,Yn-1 )。
  2. 如果xm!=yn,则LCS( X,Y )= max{ LCS ( Xm-1, Y ), LCS ( X, Yn-1 ) }

    LCS问题也具有重叠子问题性质:为找出X和Y的一个LCS,可能需要找X和Yn-1的一个LCS以及Xm-1和Y的一个LCS。但这两个子问题都包含着找Xm-1和Yn-1的一个LCS,等等.

DP最终处理的还是数值(极值做最优解),找到了最优值,就找到了最优方案;为了找到最长的LCS,我们定义dp[i][j]记录序列LCS的长度,合法状态的初始值为当序列X的长度为0或Y的长度为0,公共子序列LCS长度为0,即dp[i][j]=0,所以用i和j分别表示序列X的长度和序列Y的长度,状态转移方程为

  1. dp[i][j] = 0  如果i=0或j=0
  2. dp[i][j] = dp[i-1][j-1] + 1  如果X[i-1] = Y[i-1] (X[i-1]就是X数组中的第i个)
  3. dp[i][j] = max{ dp[i-1][j], dp[i][j-1] }  如果X[i-1] != Y[i-1]
#include<iostream>#include<string>#include<vector>using namespace std;int main(){        string strx,stry;cin>>strx>>stry;int nx = strx.length();int ny = stry.length();vector<vector<int>> vecall;for (int i=0;i<=nx;i++){vector<int> vec(ny+1,0);vecall.push_back(vec);}for (int i=1;i<=nx;i++){for (int j=1;j<=ny;j++){if (strx[i-1]==stry[j-1]){vecall[i][j]=vecall[i-1][j-1]+1;}else if (vecall[i-1][j]>vecall[i][j-1]){vecall[i][j]=vecall[i-1][j];}else{vecall[i][j]=vecall[i][j-1];}}}int ans = vecall[nx][ny];//最长公共子序列长度cout<<ans<<endl;int i=nx;int j=ny;string lcs(ans,' ');while (i && j)//找出最长公共子序列{if (strx[i-1]==stry[j-1] && vecall[i][j]==vecall[i-1][j-1]+1){lcs[--ans]=strx[i-1];i--,j--;}else if (vecall[i-1][j]>vecall[i][j-1]){i--;}else{j--;}}for (i=0;i<lcs.length();i++){cout<<lcs[i];//打印最长公共子序列}return 0;}


阅读全文
0 0
原创粉丝点击