zoukankan      html  css  js  c++  java
  • 51Nod-1006【LCS】+【输出路径】模板题

    题目链接: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

  • 相关阅读:
    第四章
    第二章
    第三章
    第一章
    第十章心得
    第九章心得
    第八章心得
    第七章心得
    第六章心得
    第五章心得
  • 原文地址:https://www.cnblogs.com/00isok/p/9058040.html
Copyright © 2011-2022 走看看