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;
    }

           

  • 相关阅读:
    mongoDB的常用语法
    Linux系统清除缓存
    110:类视图讲解
    109:大型CSV文件的处理方式
    108:生成和下载csv文件
    107:JsonResponse用法详解
    106:HttpResponse对象讲解
    104~105:HttpRequest对象讲解和QueryDict的用法讲解
    103:重定向详解
    102:限制请求method装饰器
  • 原文地址:https://www.cnblogs.com/zuoyou151/p/9029400.html
Copyright © 2011-2022 走看看