动态规划 最长公共子序列LCS

状态转移方程如下:


刚开始完全不理解当xi!=yj时,为什么Cij要等于疑问

以s1作为标准,当前已经s1下标为i(即i不变,j在变化),匹配时s2的j是依次递增的,那么当s1i!=s2j时,那么此时Cij的值就是C[i,j-1]的值

以s2作为标准,当前已经s2下标为j(即j不变,i在变化),匹配时s1的i是依次递增的,那么当s1i!=s2j时,那么此时Cij的值就是C[i-1,j]的值

正因为Cij可视为以上两种不同标准的匹配,所以Cij就取其中最大那个值作为Cij


推荐博文:1点击打开链接       2点击打开链接  感谢两位dalao讲解!谢谢! 


#include<stdio.h>
#include<string>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
char s1[100],s2[100];
int maxlen[100][100];//用来保存每个状态的最长公共子序列长度
int flag[100][100];//用来记录路径,方便输出最长公共子序列
void LCS()
{
    int i,j,k,len1,len2;
    len1=strlen(s1);
    len2=strlen(s2);
    for(i=0; i<=len1; i++)//当i=0或者j=0时,maxlen赋为0
        maxlen[i][0]=0;
    for(i=0; i<=len2; i++)
        maxlen[0][i]=0;

    memset(flag,0,sizeof(flag));
    for(i=1; i<=len1; i++)
    {
        for(j=1; j<=len2; j++)
        {
            if(s1[i-1]==s2[j-1])//注意数组下标,amxlen矩阵起始位置为(1,1),而s1,s2数组起始位置为0
            {
                maxlen[i][j]=maxlen[i-1][j-1]+1;
                flag[i][j]=1;//说明这个位置上s1[i]==s2[j],也可以说是这个值从斜上方而来
            }
            else
            {
                if(maxlen[i-1][j]>=maxlen[i][j-1])
                {
                    maxlen[i][j]=maxlen[i-1][j];
                    flag[i][j]=2;//这个值从“上”方而来
                }
            }
            else
            {
                maxlen[i][j]=maxlen[i][j-1];
                flag[i][j]=3;//这个值从“左边”而来
            }
        }
    }
}

/*for(i=1; i<=len1; i++)
{
    for(j=1; j<=len2; j++)
    {
        printf("%d ",flag[i][j]);
    }
    printf("
");
}
用来查看flag矩阵
*/


}
void getLCS()
{
    int i,j,k,len1,len2;
    i=strlen(s1);
    j=strlen(s2);
    char ans[100];
    k=0;
    while(i>0&&j>0)
    {
        if(flag[i][j]==1)
        {
            ans[k++]=s1[i-1];//注意数组下标,flag矩阵起始位置为(1,1),而s1,s2数组起始位置为0
            i--;
            j--;
        }
        else if(flag[i][j]==2)i--;
        else j--;
    //实际上就是在寻找flag为'1'的位置,并将那个位置上的s1(或者s2,因为当flag==1时,s1[i]==s2[j])存入结果数组中
    }
    for(j=k-1; j>=0; j--)//倒着输出lcs,因为我们是从尾向头开始找lcs子序列的
        printf("%c",ans[j]);
    printf("
");
}


int main()
{
    int len1,len2,i,j;
    while(scanf("%s%s",s1,s2)!=EOF)
    {
        LCS();
        printf("%d
",maxlen[strlen(s1)][strlen(s2)]);
        getLCS();
    }


    return 0;
}
/*
13456778
357486782

abcbdab
bdcaba
*/


flag矩阵里面那个方向,就是下面这个图的意思(借用上面大佬博文的图):


”斜上方“即是当前s1i==s2j,maxlen{i,j}=maxlen[i-1,j-1]+1;

”左方“即是当前最大值来自左边,maxlen{i,j}=maxlen[i,j-1];
上方“即是当前最大值来自上方,maxlen{i,j}=maxlen[i-1,j];

原文地址:https://www.cnblogs.com/hjch0708/p/7554822.html