最长公共子序列 (LCS)

继上次讲完求LCS长度后,来更新一篇具体求LCS的求法。

in:

abcicba
abdkscab
out:
abca

我们已经知道lcs中的状态转移方程为:

for(int i=0;i<=a;i++)
        {
            for(int j=0;j<=b;j++)
            {
                if(i==0||j==0)
                {
                    dp[i][j]=0;
                    continue;
                }
                if(s1[i-1]==s2[j-1])
                    dp[i][j]=dp[i-1][j-1]+1;
                else
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
            }
        }

得出,在进行dp时,dp[i][j]的状态由三种可能的状态转移过来,第一种状态表示第一个序列的前i-1个字符与第二个序列前j-1个字符的公共子序列加上最后一个字符的录入状态,如果最后的一个字符相等则录入状态为1;第二种状态表示不录入第二个序列的第j个字符时的最长公共子序列;第三种状态表示不录入第一个序列的第i个字符时的最长公共子序列。

那么有:

while(i!=0 && j!=0)

    {

        if(a[i-1] == b[j-1])//对应第一种情况

        {

            c[z++] = a[--i];//将a[i-1]录入c中

            j--;

        }

        else if(dp[i-1][j] < dp[i][j-1])//第二种

            j--;

        else if(dp[i][j-1] <= dp[i-1][j])//第三种

            i--;

    }

加上完整的路径打印为

#include<bits/stdc++.h>
using namespace std;
char a[1001], b[1001];
int dp[1001][1001], len1, len2;
void lcs(int i, int j)
{
    for(i=1; i<=len1; i++)
    {
        for(j=1; j<=len2; j++)
        {
            if(a[i-1] == b[j-1])
                dp[i][j] = dp[i-1][j-1] + 1;
            else if(dp[i-1][j] > dp[i][j-1])
                dp[i][j] = dp[i-1][j];
            else
                dp[i][j] = dp[i][j-1];
        }
    }
}
void getlcs()
{
    int i, j, z = 0;
    char c[1001];
    memset(c, 0, sizeof(c));
    i = len1, j = len2;
    while(i!=0 && j!=0)
    {
        if(a[i-1] == b[j-1])
        {
            c[z++] = a[--i];
            j--;
        }
        else if(dp[i-1][j] < dp[i][j-1])
            j--;
        else if(dp[i][j-1] <= dp[i-1][j])
            i--;
    }
    for(i=z-1; i>=0; i--)
        printf("%c", c[i]);
    putchar('
');
}
int main()
{
    while(~scanf(" %s", a))
    {
        scanf(" %s", b);
        memset(dp, 0, sizeof(dp));
        len1 = strlen(a);
        len2 = strlen(b);
        lcs(len1, len2);
        getlcs();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/iloveysm/p/12274529.html