• dp之最长公共子序列


    例1:给你两个字符串,找出最长子序列的长度。

    对于字符串t, 字符串s,给定特定的i, j代表t,s的位置,只存在三种情况:

      1. i == 0 ||  j==0, M[i][j] = 0;

      2. t[i] == s[j], M[i][j] = min(M[j-1][j-1] + 1, M[i-1][j], M[i][j-1]);//.....不知道怎么解释。。。。

      3. t[i] != s[j] , M[i][j] = min(M[i-1][j], M[i][j-1]);//。。。。。

    经典dp题

    代码:

    #include <iostream>
    #include <cstring>
    using namespace std;
    string s, t;
    int M[1000][1000];
    int hasgo[1000][1000];
    int dp(int a, int b)
    {
        if(hasgo[a][b] > 0) return M[a][b];
        if(!a || !b) return 0;
        if(s[a-1] == t[b-1])
        {
            M[a][b] = max(dp(a-1, b-1) + 1, M[a][b]);
        }
        M[a][b] = max(M[a][b], dp(a, b - 1));
        M[a][b] = max(M[a][b], dp(a - 1, b));
        hasgo[a][b] = 1;
        return M[a][b];
    }
    int main()
    {
        while(cin >> s >> t)
        {
            memset(M, 0, sizeof(M));
            memset(hasgo, 0, sizeof(hasgo));
            cout << dp(s.size(), t.size()) << endl;
        }
        return 0;
    }

    升级版最长公共子序列

    例2:给你n条字符串,找出最长公共子序列的长度。

    如果按照上面的思路,如果是三条,弄个三维数组就好了,几条字符串就弄几维数组,但这题维数没法确定,,,就涉及到dp中一个常用的技巧,,子问题编码,对于A(a[1], a[2], a[3] .... a[n])代表

    各个串中的位置,给这个数组独一无二的编码: index = a[1] + a[2] * len[1] + a[3] * len[2] + ... + a[n] * len[n-1],   这样一个一维数组M[index]就可以表示每种状态的最长子串了。

    (len 是各个串的长度)
    1. 有一个为0, M[index] = 0;

    2. 都相等的时候, M[index] = min(M[index], M[index'] + 1), index' = a[i'] = a[i] - 1;for(int i = 1; i <= n; i++),A[i]--; M[index] = M[index'];

    3.for(int i = 1; i <= n; i++),A[i]--; M[index] = M[index'];(当然,是在len1 * len2 * len 3 *...在可接受的范围内。。。)

    代码

    #include <iostream>
    #include <cstring>
    using namespace std;
    ///多个字符串找最大公共子串,对于每一个串确定的位置(d1, d2, d3,...,dn),可能存在三种情况,当前位置的字母都是相同的,
    int *len, *A, *M, *xishu;///字符串长度, 系数, 最长公共子序列,系数单位
    char str[105][105];
    int n;
    int hasgo[30005];
    int solve(int index)
    {
        if(hasgo[index] > 0) return M[index];
        for(int i = 0; i < n; i++)
            if(!A[i]){hasgo[index] = 1; return 0;}
        int ok = 1;
        for(int i = 0; i < n - 1; i++)
            if(str[i][A[i]] != str[i+1][A[i+1]]) ok = 0;
        if(ok)
        {
            int ii = index;
            for(int i = 0; i < n; i++)
             {
                 A[i]--;
                 ii -= xishu[i];
             }
            M[index] = max(solve(ii) + 1, M[index]);
            for(int i = 0; i < n; i++)
                A[i]++;
        }
        int ii = index;
        for(int i = 0; i < n; i++)
        {
            ii -= xishu[i];
            A[i]--;
            M[index] = max(solve(ii), M[index]);
            A[i]++;
            ii += xishu[i];
        }
        hasgo[index] = 1;
        return M[index];
    }
    int main()
    {
        int t;
        cin >> t;
        while(t--)
        {
            cin >> n;
            len = new int[n];
            A = new int[n];
            M = new int[30005]();
            xishu = new int[n];
            int ii = 0;
           // memset(M, 0, sizeof(M)*30005);
            memset(hasgo, 0, sizeof(hasgo));
            for(int i = 0; i < n; i++)
            {
                cin >> str[i];
            }
            for(int i = 0; i < n; i++)
            {
                len[i] = strlen(str[i]);
                A[i] = len[i];
                xishu[i] = (!i ? 1 : xishu[i-1]*len[i-1]);
                ii += A[i] * xishu[i];
            }
            cout << solve(ii) << endl;
            delete []M;
            delete []A;
            delete []xishu;
            delete []len;
        }
    }
    print “ 欢迎来到渣小狼的博客,这既是博客,也是日记,里面记录了小狼的学习经历还有一些小狼的见解,非常希望每一个来到这里的人能够留下只言片语,更加的希望留下的是对于小狼的不足的补充,谢谢(*^__^*) 嘻嘻……”
  • 相关阅读:
    case when then 根据不同条件 查询不同的数据 相当于 if-else if-else
    完美的拼接sql语句,中间可以加字符等东西,
    C++抽象类
    C #引用NuGet程序包MySQLData问题
    win10磁盘100%占用解决方法
    C# ASP.NetCore 检测到包降级
    VS 命令“npm install”已退出的问题
    序列化和反序列化含义
    数据库MySQL忘记本地密码
    MongoDB授予权限
  • 原文地址:https://www.cnblogs.com/wolf-yasen/p/6613423.html
Copyright © 2020-2023  润新知