最长公共子序列lcs

Posted xiongtao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最长公共子序列lcs相关的知识,希望对你有一定的参考价值。

本来想总结的,发现总结不来,不会组织语言,就水水的贴一下大佬总结的博客:https://blog.csdn.net/so_geili/article/details/53737001

一道简单的模板题:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1006

题目意思就是求两个字符串的任意一个最大公共子序列

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
char a[1005],b[1005];
int dp[1005][1005],r[1005][1005];
void dplcs(int la,int lb)
{
    for(int i=0;i<=la;i++)
        dp[i][0]=0;
    for(int j=1;j<=lb;j++)
        dp[0][j]=0;
    for(int i=1;i<=la;i++)
        for(int j=1;j<=lb;j++)
        {
            if(a[i-1]==b[j-1])//从对角线过来的 
            {
                dp[i][j]=dp[i-1][j-1]+1;
                r[i][j]=1;
            }
            else if(dp[i-1][j]>=dp[i][j-1])//从上面过来的 
            {
                dp[i][j]=dp[i-1][j];
                r[i][j]=3;
            }
            else//从左边过来的 
            {
                dp[i][j]=dp[i][j-1];
                r[i][j]=2;
            }
        }
}
void printlcs(int la,int lb)//递归实现 
{
    if(la==0||lb==0)
        return ;
    if(r[la][lb]==1)
    {
        printlcs(la-1,lb-1);
        cout<<a[la-1];//反向输出 
    }
    else if(r[la][lb]==3)
        printlcs(la-1,lb);
    else
        printlcs(la,lb-1);
}
int main()
{
    cin>>a>>b;
    memset(r,0,sizeof(r));
    int la=strlen(a);
    int lb=strlen(b);
    dplcs(la,lb);
    printlcs(la,lb);
    cout<<endl;
    return 0;
}

第二题:https://vjudge.net/contest/236677#problem/B

题目意思反过来的,给你dp矩阵,求任意符合的两个字符串

思路:先固定a,字符串很小,所以直接赋"abcd...",根据dp矩阵来确定b,但有一个问题就是b[j]可能已经确定了,那么只能讲对应的a[i]改成b[j],有连锁反应,所以要

遍历此时的a,b字符串,将等于a[i]都改成b[j]。在最后将没有确定的b[j]都随意赋没有出现的字母就行了

#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int dp[105][105];
char a[105],b[105];
bool vis_b[105];//b是否确定 
int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        memset(vis_b,0,sizeof(vis_b));
        for(int i=0;i<=n;i++)
            for(int j=0;j<=m;j++)
                cin>>dp[i][j];
        for(int i=0;i<n;i++)
            a[i]=a+i;//令a为abcd... 
        a[n]=b[m]=;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                if(dp[i][j]==dp[i-1][j-1]+1&&dp[i][j]!=max(dp[i-1][j],dp[i][j-1]))//b[j-1]==a[i-1]
                {
                    if(!vis_b[j])//b[j-1]还没确定值,就等于a[i-1] 
                    {
                        b[j-1]=a[i-1];
                        vis_b[j]=1;
                    }
                    else//b[j-1]有值了,改变b和a中和a[i-1]相同的值变为b[j-1](因为a[i-1]要等于b[j-1],与a[i-1]相同的值也要改变) 
                    {
                        for(int k=0;k<m;k++)
                            if(b[k]==a[i-1])
                                b[k]=b[j-1];
                        for(int k=0;k<n;k++)
                            if(a[k]==a[i-1])
                                a[k]=b[j-1];
                    }
                }
            }
        bool vis[26];//判断字母是否用过 
        memset(vis,0,sizeof(vis));
        for(int i=0;i<n;i++)
            vis[a[i]-a]=1;
        int t;
        for(int i=0;i<26;i++)
            if(!vis[i])//找到一个没用过的 
            {
                t=i;
                break;
            }
        for(int i=1;i<=m;i++)
            if(!vis_b[i])//还没有值的b可以用一个没用过的值代替所有的值(因为这些b和a已经没有关系了) 
                b[i-1]=t+a;
        cout<<a<<endl<<b<<endl;
    }
    return 0;
}

 

 

以上是关于最长公共子序列lcs的主要内容,如果未能解决你的问题,请参考以下文章

每日一题-——最长公共子序列(LCS)与最长公共子串

最长公共子序列(LCS)

LeetCode(LCSி)最长公共子序列&变形应用

最长公共子序列 LCS

最长公共子序列(LCS)

最长公共子序列(LCS)