LCS问题

Posted

tags:

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

最长公共子序列问题

核心代码:

for(int i=1;i<=len1;i++)
for(int j=1;j<=len2;j++)
{
    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]);
}

UVA10405 Longest Common Subsequence

模板题

代码:

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
#define pb push_back
#define mp make_pair
#define se second
#define fs first
#define LL long long
#define CLR(x) memset(x,0,sizeof x)
#define MC(x,y) memcpy(x,y,sizeof(x))  
#define SZ(x) ((int)(x).size())
#define FOR(it,c) for(__typeof((c).begin()) it=(c).begin();it!=(c).end();it++)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1 
typedef pair<int,int> P;
const double eps=1e-9;
const int maxn=200100;
const int mod=1e9+7;
const int INF=1e9;

char s1[1050],s2[1050];
int dp[1050][1050];
int main()
{
    while(gets(s1)&&gets(s2))
    {
        int len1=strlen(s1);
        int len2=strlen(s2);
        CLR(dp);
        for(int i=1;i<=len1;i++)
        for(int j=1;j<=len2;j++)
        {
            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]);
        }
        printf("%d\n",dp[len1][len2]);
    }
    return 0;
}

UVA10252 Common Permutation

求一个最长子序列。使得子序列的全排列中有一个(可以不相同)是2个字符串的子序列.

仔细思考并不是LCS问题,直接模拟有多少个字符相同即可

代码:

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
#define pb push_back
#define mp make_pair
#define se second
#define fs first
#define LL long long
#define CLR(x) memset(x,0,sizeof x)
#define MC(x,y) memcpy(x,y,sizeof(x))  
#define SZ(x) ((int)(x).size())
#define FOR(it,c) for(__typeof((c).begin()) it=(c).begin();it!=(c).end();it++)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1 
typedef pair<int,int> P;
const double eps=1e-9;
const int maxn=200100;
const int mod=1e9+7;
const int INF=1e9;

char s1[1050],s2[1050];
map<int,int> m,m2;
int num[30];

int main()
{
    while(gets(s1)&&gets(s2))
    {
        m.clear();m2.clear();
        int len1=strlen(s1);
        int len2=strlen(s2);
        for(int i=0;i<len1;i++) m[s1[i]-a]++;
        for(int i=0;i<len2;i++) m2[s2[i]-a]++;
        for(int i=0;i<26;i++)
        {
             num[i]=min(m[i],m2[i]);
             for(int j=0;j<num[i];j++) printf("%c",a+i);
        }
        printf("\n");
    }
    return 0;
}

UVA 531 Compromise

LCS问题+路径输出

路径输出标记每个位置的转移过程,然后递归输出

代码:

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
#define pb push_back
#define mp make_pair
#define se second
#define fs first
#define LL long long
#define CLR(x) memset(x,0,sizeof x)
#define MC(x,y) memcpy(x,y,sizeof(x))  
#define SZ(x) ((int)(x).size())
#define FOR(it,c) for(__typeof((c).begin()) it=(c).begin();it!=(c).end();it++)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1 
typedef pair<int,int> P;
const double eps=1e-9;
const int maxn=105;
const int mod=1e9+7;
const int INF=1e9;

int dp[maxn][maxn];
int flag[maxn][maxn];
int l1,l2;
string s1[maxn],s2[maxn];

void print_path(int x,int y)
{
    if(x==0||y==0) return;
    if(flag[x][y])
    {
        print_path(x-1,y-1);
        cout<<s1[x-1];
        if(dp[x][y]!=dp[l1][l2]) cout<<" ";
    }
    else if(dp[x][y]==dp[x-1][y]) print_path(x-1,y);
    else  print_path(x,y-1);
}

int main()
{
    l1=l2=0;
    while(cin>>s1[l1++]){
        while(cin>>s1[l1]&&s1[l1]!="#") l1++;
        while(cin>>s2[l2]&&s2[l2]!="#") l2++;
        CLR(dp);CLR(flag);
        for(int i=1;i<=l1;i++)
        for(int j=1;j<=l2;j++)
        {
            if(s1[i-1]==s2[j-1])
            {
                dp[i][j]=dp[i-1][j-1]+1;
                flag[i][j]=1;
            }
            else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
        }
        print_path(l1,l2);
        cout<<endl;
        l1=l2=0;
    }
    return 0;
}

UVA10723 Cyborg Genes

LCS变种问题

仔细分析发现:最短目标字符串等于两个字符串长度的和减去最长公共子序列。dp[i][j]表示

那么数目的求和就等于最长公共子序列的路径组合数目。num[i][j]表示

首先初始化 num[0][i]=num[i][0]=1

1.s1[i]==s1[j] num[i][j]=num[i-1][j-1]

2.dp[i-1][j]>dp[i][j-1] num[i][j]=num[i-1][j]

3.dp[i-1][j]<dp[i][j-1] num[i][j]=num[i][j-1]

4.dp[i-1][j]==dp[i][j-1] num[i][j]=num[i-1][j]+num[i][j-1]

代码

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
using namespace std;
#define pb push_back
#define mp make_pair
#define se second
#define fs first
#define LL long long
#define CLR(x) memset(x,0,sizeof x)
#define MC(x,y) memcpy(x,y,sizeof(x))  
#define SZ(x) ((int)(x).size())
#define FOR(it,c) for(__typeof((c).begin()) it=(c).begin();it!=(c).end();it++)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1 
typedef pair<int,int> P;
const double eps=1e-9;
const int maxn=200100;
const int mod=1e9+7;
const int INF=1e9;

int dp[50][50],num[50][50],len1,len2;
char s1[50],s2[50];

int main()
{
    int n,Case=1;
    scanf("%d",&n); getchar();
    while(n--)
    {
        gets(s1);gets(s2);
        int len1=strlen(s1),len2=strlen(s2);
        CLR(dp);CLR(num);
        for(int i=0;i<50;i++) num[i][0]=num[0][i]=1;
        for(int i=1;i<=len1;i++)
        for(int j=1;j<=len2;j++)
        {
            if(s1[i-1]==s2[j-1])
            {
                dp[i][j]=dp[i-1][j-1]+1;
                num[i][j]=num[i-1][j-1];
            }
            else if(dp[i-1][j]>dp[i][j-1])
            {
                dp[i][j]=dp[i-1][j];
                num[i][j]=num[i-1][j];
            }
            else if(dp[i-1][j]<dp[i][j-1])
            {
                dp[i][j]=dp[i][j-1];
                num[i][j]=num[i][j-1];
            }
            else
            {
                dp[i][j]=dp[i][j-1];
                num[i][j]=num[i][j-1]+num[i-1][j];
            }
        }
        printf("Case #%d:",Case++);
        printf(" %d %d\n",len1+len2-dp[len1][len2],num[len1][len2]);
    }
}

 

以上是关于LCS问题的主要内容,如果未能解决你的问题,请参考以下文章

经典问题LCS(最大公共子串问题)C代码实现

LCS问题

最长公共子序列(LCS),求LCS长度和打印输出LCS

使用 DP 查找 LCS

LCS的数量

最长公共上升子序列 (LIS+LCS+记录)