zoukankan      html  css  js  c++  java
  • 动态规划作业-最长公共子序列问题

    问题:对给定序列X=(x1,x2,...xm)和序列Z=(z1,z2,...zk),Z是X的子序列当且仅当存在一个递增下标序列(i1,i2,...ik)

              使得对于所有j=1,2,,,k有zj=xij(1<=xij<=m)。例如序列(a,b,c,b,d,a,b)的一个子序列(b,c,d,b)

              相应的递增下标序列(2,3,5,7)

              给定两个序列X和Y,当序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列

    定义子问题:设L(m,n)表示序列X=(x1,x2,...xm和Y=(y1,y2,...yn)的最长公共子序列的长度,显然

                          初始子问题是序列X和Y至少有一个空序列,即:

                          L(0,0)=L(0,j)=L(i,0)=0,     1<=i<=m,1<=j<=n

    动态规划函数:

                          L(i,j)=L(i-1,j-1)+1                 xi=yj,i>=1,j>=1

                          L(i,j)=max{(L(i-1,j),L(i,j-1)}   xi!=yj,i>=1,j>=1

    为了得到序列X和Y的最长公共子序列,设二维表S(m,n)记载求解过程中的状态变化

                         S(i,j)=1   xi=yj

                        S(i,j)=2   xi!=yj,L(i,j-1)>=L(i-1,j)

                        S(i,j)=3   xi!=yj,  L(i,j-1)<L(i-1,j)

    若S(i,j)=1,则下一个搜索方向是S(i-1,j-1)

    若S(i,j)=2,则下一个搜索方向是S(i,j-1)

    若S(i,j)=3则下一个搜索方向是S(i-1,j)

     算法:

           输入:两个序列x和y

          输出:最长公共子序列及其长度

             1.循环变量i从0到l1重复下列操作

                  L[i][0]=S[i][0]=0;

              2.循环变量i从0到l2重复下列操作

                  L[0][i]=S[0][i]=0;

              3.循环变量i从1到l1重复下列操作

                 3.1循环变量j从1到l2

                       3.1.1如果x[i]==y[j]

                               S[i][j]=1; L[i][j]=L[i-1][j-1]+1

                       3.1.2否则如果 L[i][j-1]>=L[i-1][j]

                              S[i][j]=2; L[i][j]=L[i][j-1]

                        3.1.3否则 S[i][j]=3;L[i][j]=L[i-1][j]

                   4.使i=l1,j=l2,k=0;直到i<0 或者j<0,用字符数组path记录最长公共子序列

                      4.1如果S[i][j]==1 path[k++]=x[i],i--,j--;

                      4.2否则,如果S[i][j]=2 j--;

                       4.3否则 i--;

    void dp_com(char x[], char y[],int l1,int l2) {
        int L[100][100];
        int S[100][100];
        char path[100];
        for (int i = 0; i <=l1; i++)
            L[i][0] = S[i][0] = 0;
        for (int i = 0; i <=l2; i++)
            L[0][i] = S[0][i] = 0;
        for (int i = 1; i <=l1; i++) {
            for (int j = 1; j <=l2; j++) {
                if (x[i] == y[j]) {
                    S[i][j] = 1;
                    L[i][j] = L[i - 1][j - 1] + 1;
                }
                else if (L[i][j-1] >=L[i-1][j]) {
                    S[i][j] = 2;
                    L[i][j] = L[i][j-1];
                }
                else {
                    S[i][j] = 3;
                    L[i][j] = L[i-1][j];
                }
            }
        }
        cout << L[l1][l2] << endl;
        int i = l1, j = l2;
        int k = 0;
        while (i >0 && j >0) {
            if (S[i][j] == 1) {
                path[k++] = x[i];
                i--;
                j--;
            }
            else if (S[i][j] == 2) j--;
            else i--;
        }
        for (i = k-1; i >= 0; i--)
            cout << path[i];
        cout << endl;
    }

           

  • 相关阅读:
    UVALive 6909 Kevin's Problem 数学排列组合
    UVALive 6908 Electric Bike dp
    UVALive 6907 Body Building tarjan
    UVALive 6906 Cluster Analysis 并查集
    八月微博
    hdu 5784 How Many Triangles 计算几何,平面有多少个锐角三角形
    hdu 5792 World is Exploding 树状数组
    hdu 5791 Two dp
    hdu 5787 K-wolf Number 数位dp
    hdu 5783 Divide the Sequence 贪心
  • 原文地址:https://www.cnblogs.com/zuoyou151/p/9029400.html
Copyright © 2011-2022 走看看