51Nod-1006LCS+输出路径模板题

Posted is_ok

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51Nod-1006LCS+输出路径模板题相关的知识,希望对你有一定的参考价值。

题目链接:https://vjudge.net/contest/225715#problem/B

转载于>>>

 

题目大意:

给出两个序列,要求输出它们的最长公共子序列。

解题思路:

最长公共子序列模板题~

我们用dp[i][j]表示到a串第i个字符, b串第j个字符的最大匹配字符数,那么状态转移方程为:

dp[i][j]=dp[i-1][j-1]+1      a[i]==b[j]

dp[i][j]=max(dp[i][j-1], dp[i-1][j])   a[i]!=b[j]

我们可以这样理解:dp[i][j]表示第a串前i个字符与b串前j个字符的最大匹配数,dp[i-1][j-1]表示a字符前i-1个字符与b串前j-1个字符的最大匹配数

如果a[i]=b[j],那么很明显dp[i][j]=dp[i-1][j-1]+1;

若a[i]!=b[j],我们假设a, b的最大匹配串为c,显然a[i], b[j]不能同时作为c的最后一个字符,那么最优匹配情况即为a[i]为c的最后一个字符或者b[j]为c的最后一个字符(这点不大好理解),即

dp[i][j]=dp[i][j-1]    a[i]是c的最后一个字符即匹配的末尾字符

dp[i][j]=dp[i-1][j]    b[j]是c的最后一个字符即匹配的末尾字符 (其实当a[i], b[j]都不是c的最后一个字符时即a[i], b[j]都不匹配时dp[i][j]=dp[i-1][j-1])

又dp要取最大值 ,即dp[i][j]=max(dp[i][j-1], dp[i-1][j])

题目还要求要输出一个最优匹配串,这个我们用vis[][]数组在dp过程中记录一下路径就好啦~

 

非递归输出路径

#include <bits/stdc++.h>
using namespace std;
#define MAXN 1010
int dp[MAXN][MAXN];
int vis[MAXN][MAXN];
string stra, strb;
char output[MAXN]; int cur = 0;

void getlcs(int i, int j)
{
    while (i>0&&j>0)          //逆推取出vis中保存的路径
    {
        if (vis[i][j]==1) {
            output[cur++] = stra[i - 1];
            i--; j--;
        }
        else if (vis[i][j] == 2) {
            j--;
        }
        else {
            i--;
        }
    }
}

int main()
{
    cin >> stra >> strb;
    int lena = stra.length();
    int lenb = strb.length();
    for (int i = 1; i <= lena; i++){
        for (int j = 1; j <= lenb; j++) {
            if (stra[i - 1] == strb[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
                vis[i][j] = 1;             //vis数组标记路径
            }
            else {
                if (dp[i - 1][j] < dp[i][j - 1]) {
                    dp[i][j] = dp[i][j - 1];
                    vis[i][j] = 2;
                }
                else {
                    dp[i][j] = dp[i - 1][j];
                    vis[i][j] = 3;
                }
            }
        }
    }
    getlcs(lena, lenb);
    for (int i = cur - 1; i >= 0; i--)        //逆向输出
        printf("%c", output[i]);
    cout << endl;
    return 0;
}

 

递归输出路径

#include <bits/stdc++.h>
using namespace std;
#define MAXN 1010
int dp[MAXN][MAXN];
int vis[MAXN][MAXN];
string stra, strb;

void getlcs(int i, int j) { //**输出路径
    if (!i || !j) {        //因为i-1要>=0
        return;
    }
    if (vis[i][j] == 1) {
        getlcs(i - 1, j - 1);
        printf("%c", stra[i - 1]);
    }
    else if (vis[i][j] == 2) {
        getlcs(i, j - 1);
    }
    else {
        getlcs(i - 1, j);
    }
}

int main()
{
    cin >> stra >> strb;
    int lena = stra.length();
    int lenb = strb.length();
    for (int i = 1; i <= lena; i++){
        for (int j = 1; j <= lenb; j++) {
            if (stra[i - 1] == strb[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
                vis[i][j] = 1;             //vis数组标记路径
            }
            else {
                if (dp[i - 1][j] < dp[i][j - 1]) {
                    dp[i][j] = dp[i][j - 1];
                    vis[i][j] = 2;
                }
                else {
                    dp[i][j] = dp[i - 1][j];
                    vis[i][j] = 3;
                }
            }
        }
    }
    getlcs(lena, lenb);
    cout << endl;
    return 0;
}

 

 

2018-05-18

以上是关于51Nod-1006LCS+输出路径模板题的主要内容,如果未能解决你的问题,请参考以下文章

模板51nod 1006 最长公共子序列Lcs

51Nod 1006 最长公共子序列Lcs

51nod 1006 最长公共子序列Lcs(dp+string,无标记数组实现)

51Nod-1006 最长公共子序列Lcs

最长公共子序列Lcs (51Nod - 1006)

ACM/ICPC 之 最长公共子序列计数及其回溯算法(51Nod-1006(最长公共子序列))