zoukankan      html  css  js  c++  java
  • 动态规划之最长公共子序列

    首先需要说一下的是,什么是公共子序列。子串的概念就是,一个字符串中连续的一部分, 而 子序列,可以是不连续的。

    •一个给定序列的子序列是在该序列中删去若干元素后得到的序列。
    •给定两个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。
    •最长公共子序列:公共子序列中长度最长的子序列。
    【穷举法】
    •对于每一个Xm的子序列,验证它是否是Yn的子序列.
    •Xm有2m个子序列
    •每个子序列需要o(n)的时间来验证它是否是Yn的子序列.
    –从Yn的第一个字母开始扫描下去,如果不是则从第二个开始
    •运行时间: o(2^n*2^m)
     
     
    【动态规划】
    •两个字符串【横向,纵向排列】
    ABDTFGHFEABADG
    BTHEBDCEFG
       A B DT F G H F EA B A D G
    B 0 1 1 1 1 1 1 1 1 1 1 1 1 1
    T 0 1 1 2 2 2 2 2 2 2 2 2 2 2
    H 0 1 1 2 2 2 3 3 3 3 3 3 3 3
    E 0 1 1 2 2 2 3 3 4 4 4 4 4 4
    B 0 1 1 2 2 2 3 3 4 4 5 5 5 5
    D 0 1 2 2 2 2 3 3 4 4 5 5 6 6
    C 0 1 2 2 2 2 3 3 4 4 5 5 6 6
    E 0 1 2 2 2 2 3 3 4 4 5 5 6 6
    F 0 1 2 2 3 3 3 4 4 4 5 5 6 6
    G 0 1 2 2 3 4 4 4 4 4 5 5 6 7

    状态迁移方程:

    c[i][j] 是用来保存截止到X[i],Y[j]的时候的最长公共子序列的长度。

    c[i][j] =0,                                  i = j =0;

    c[i][j] = c[i-1][j-1]+1 ,               i>0,j>0 && Xi = Yj

    c[i][j] = max(c[i-1][j],c[i][j-1]),  i>0,j>0 && Xi ≠ Yj

    #include<iostream>
    #include<string>
    #include<algorithm>
    using namespace std;
    const int maxn = 1000;
    string str1,str2;
    int c[maxn][maxn];
    int n;int m;
    void solve()
    {
    
        for(int i = 0;i<n;i++)
        {
    
            for(int j = 0;j<m;j++)
            {
                if(str1[i] ==str2[j])
                    c[i+1][j+1] = c[i][j] + 1;
               else
               c[i+1][j+1] = max(c[i+1][j],c[i][j+1]);
            }
        }
    
    }
    
    int main()
    {
        cin>>str1>>str2;
         n = str1.length();
         m = str2.length();
        solve();
        cout<<c[n][m]<<endl;
    
        return 0;
    }
    

     后来仔细想想,没那么复杂其实也,只要自己肯动脑子……

    昨天晚上那个心急啊,想想该如何输出其中的一个最大公共子序列呢……

    矩阵 b[i, j]:存放当前的路径,也就是说c[i][j]是如何得来的。

    如果c[i][j] = c[i-1][j-1] 也就是对角线的关系;b[i][j] 标记为 '↖' b[i][j]  = 'S';

    如果c[i][j] = c[i][j-1] 也就是左右的关系 ,b[i][j] 标记为 '←' b[i][j]  = 'L';

    如果c[i][j] = c[i-1][j] 也就是上下的关系,b[i][j] 标记为 '↑' b[i][j]  = 'U';

     例如:

      B D C A B A

    A U U U S L S
    B S  L L U S L
    C U U S L U U
    B S U U U S L
    D U S U U U U
    A U U U S U S
    B S U U U S U

    从最后一个开始查找 U→S→U→S→L→S→L→S其中S对应的str1的元素就是其中的一条最长公共子子序列。

    使用递归的办法,遇到一个S就压入栈……

    #include<iostream>
    #include<string>
    #include<algorithm>
    using namespace std;
    const int maxn = 1000;
    string str1,str2;
    int c[maxn][maxn];
    char b[maxn][maxn];
    int n;int m;
    void printLCS(int i, int j)
    
    {
    
        if(i==0 || j==0)
    
            return;
    
        if(b[i][j] == 'S')
    
        {
    
            printLCS(i-1, j-1);
    
            cout<<str1[i-1]<<' ';
    
        }
    
        else
    
        {
    
            if(b[i][j] == 'U')
    
                printLCS(i-1, j);
    
            else
    
                printLCS(i, j-1);
    
        }
    
    }
    void solve()
    {
    
        for(int i = 0;i<n;i++)
        {
    
            for(int j = 0;j<m;j++)
            {
                if(str1[i] ==str2[j])
                {
                    c[i+1][j+1] = c[i][j] + 1;
                    b[i+1][j+1] = 'S';
                }
               else if(c[i+1][j]>c[i][j+1])
               {
                    c[i+1][j+1] = c[i+1][j];
                    b[i+1][j+1] = 'L';
               }
               else
               {
                    c[i+1][j+1] = c[i][j+1];
                    b[i+1][j+1] = 'U';
               }
            }
        }
    
    }
    
    int main()
    {
        cin>>str1>>str2;
         n = str1.length();
         m = str2.length();
        solve();
        cout<<c[n][m]<<endl;
        for(int i = 1;i<=n;i++)
        {
            for(int j = 1;j<=m;j++)
                cout<<c[i][j]<<' ';
            cout<<endl;
        }
        for(int i = 1;i<=n;i++)
        {
            for(int j = 1;j<=m;j++)
                cout<<b[i][j]<<' ';
    
            cout<<endl;
        }
        printLCS(n,m);
    
        return 0;
    }
    
  • 相关阅读:
    leetcode--Lowest Common Ancestor of a Binary Search Tree
    bzoj3675【APIO2014】序列切割
    计算机网络之面试常考
    <html>
    TCP相关面试题总结
    Java多线程之Lock的使用
    原来Java中有两个ArrayList
    Java编程规范
    一些面试基本知识(Android篇一)
    _PyUnicodeUCS4_AsDefaultEncodedString
  • 原文地址:https://www.cnblogs.com/plxx/p/3235440.html
Copyright © 2011-2022 走看看