最长公共子序列--动态规划入门

求两个序列 X{1,2, 5, 4, 。。。}和Y{1, 5, 4,,,,}中最长的共有序列。 例如X = {A,B, C, B,D, A, B}, Y={B,D,C,A,B,A} 两者的最长公共子序列为 {B,C,B, A}

分析:

这个问题是否可以分成一段一段处理呢? (即可否找出递归结构, 可见递归很重要, 也许你感觉它很基础,其实它很深奥!)。我们从X,Y的最后一个元素来考虑, 若X的最后一个元素在最长子串中(即它对最长子串有贡献), 那么有两种情况, 它和Y的最后一个元素相同, 或它与Y最后一个对最长子串有贡献的元素相等(你也许会说, 这个SB也知道, 但它偏偏很重要)。 另 c[i][j] 记录从 Xi和Yj的公共最长子序列。(这类题都是他妈的,这一个怂样,不要问我为什么)。

于是乎, 关键的递归公式横空出世。

                       当 i= 0, 或 j = 0 时, c[i][j ] = 0;

        当i, j>0, xi = yj   时, c[i][j] = c[i-1][j-1] + 1;

                       当i,j>0, xi != yj  时, c[i][j] = {c[i][j-1], c[i-1][j]}  --->就是由那个SB都知道的东西推来的!!嘿嘿!

 

#include<iostream>
#include<cstring>
using namespace std;

const int maxn = 100+5;
int b[maxn][maxn];
char x[maxn], y[maxn];
//用b[][]来记录取得最优值的路径。 
int lcsLength(char x[maxn], char y[maxn], int b[maxn][maxn])//计算最优解。 
{
    int m = x.length - 1;
    int n = y.length - 1;
    int c[m+1][n+1];
    for(int i=1; i<=m; i++) c[i][0] = 0;
    for(int i=1; i<=n; i++) c[0][i] = 0;
    for(int i=1; i<=m; i++)
    for(int j=1; j<=n; j++)
    {
        if(x[i]==y[j])
        {
            c[i][j] = c[i-1][j-1] + 1;
            b[i][j] = 1;                   
        }
        else if(c[i-1][j]>=c[i][j-1])
        {
            c[i][j] = c[i-1][j];
            b[i][j] = 2;
        }
        else
        {
            c[i][j] = c[i][j-1];
            b[i][j] = 3;
        }
    }
    return c[m][n];
}

//构造最优子序列。
void lcs(int i, int j, char x[maxn], int b[maxn][maxn])
{
    if(i==0||j==0) return;
    if(b[i][j]==1)
    {
        lcs(i-1, j-1, x, b);//又是递归, 看到了吧!! 
        printf("%c", x[i]);
    }
    else if(b[i][j]==2) lcs(i-1, j, x, b);
    else lcs(i, j-1, x, b);
} 

int main()
{
    /* 读入字符串x,y时从1读*/
} 

 

  

posted @ 2015-05-26 22:40  草滩小恪  阅读(208)  评论(0编辑  收藏  举报