• 动态规划 最长公共子序列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];

  • 相关阅读:
    webpack之理解loader
    React中需要多个倒计时的问题
    react.js中实现tab吸顶效果问题
    利用浏览器调试APP中的H5页面
    css一长串连续英文字符的换行
    纯css实现移动端横向滑动列表
    javascript数据结构——写一个二叉搜索树
    javascript数据结构——链表
    javascript数组去重
    《正则表达式必知必会(修订版)》笔记
  • 原文地址:https://www.cnblogs.com/hjch0708/p/7554822.html
Copyright © 2020-2023  润新知