zoukankan      html  css  js  c++  java
  • 动态规划———最长公共子序列(LCS)

    最长公共子序列+sdutoj2080改编:

    http://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Contest/contestproblem/cid/2788/pid/2080

    传送门 https://blog.csdn.net/sunshine_pb/article/details/21820159 

    设序列X={x1,x2,…,xm}和Y={y1,y2,…,yn}的最长公共子序列为Z={z1,z2,…,zk},

    记:    Xk为序列X中前k个连续字符组成的子序列,

    Yk为序列Y中前k个连续字符组成的子序列,

               Zk为序列Z中前k个连续字符组成的子序列,

    显然有下式成立:

    (1)若xm=yn,则zk=xm=yn,且Zk-1是Xm-1和Yn-1的最长公共子序列;

    (2)若xm≠yn且zk≠xm,则Z是Xm-1和Y的最长公共子序列;

    (3)若xm≠yn且zk≠yn,则Z是X和Yn-1的最长公共子序列。

      可见,两个序列的最长公共子序列包含了这两个序列的前缀序列的最长公共子序列。

    要找出序列X={x1,x2,…,xm}和Y={y1,y2,…,yn}的最长公共子序列,可按下述递推方式计算:

    当xm=yn时,找出Xm-1和Yn-1的最长公共子序   列,然后在其尾部加上xm即可得到X和Y的最长公共子序列;

    当xm≠yn时,必须求解两个子问题:找出Xm-1和Y的最长公共子序列以及Xm和Yn-1  的最长公共子序列,这两个公共子序列中的较长

    者即为X和Y的最长公共子序列

      设L[i][j]表示子序列Xi和Yj的最长公共子序列的长度,可得如下动态规划函数:

    L[0][0] = L[i][0] = L[0][j] = 0           (1≤i≤m,1≤j≤n)

       L[i][j]只是记录子序列的长度,要打印得到XmYn具体的最长公共子序列,设二维表S[m+1][n+1],其中S[i][j]表示在计算L[i][j]的过程中的搜索状态,并且有:

    若S[i][j]=1,表明ai=bj,则下一个搜索方向是S[i-1][j-1];

    若S[i][j]=2,表明ai≠bj且L[i][j-1]≥L[i-1][j],则下一个搜索方向是S[i][j-1];

    若S[i][j]=3,表明ai≠bj且L[i][j-1]<L[i-1][j],则下一个搜索方向是S[i-1][j]。

    举例:序列X=(a,b,c,b,d,b),Y=(a,c,b,b,a,b, d, b,b),建立两个(m+1)×(n+1)的二维表L和表S,分别存放搜索过程中得到的子序列的长

    度和状态。

    下面代码为sdutoj2080改编代码:

     1 /* */
     2 # include <bits/stdc++.h>
     3 using namespace std;
     4 
     5 int CommonOrder( int len1, int len2, char x[], char y[], char z[]);
     6 int L[501][501];
     7 int S[501][501];
     8 int main()
     9 {
    10     char a[501], b[501], z[501];
    11     int i, t, len1, len2;
    12     while( gets(a) && gets(b) )
    13     {
    14         len1 = strlen(a);
    15         len2 = strlen(b);
    16         t = CommonOrder(len1, len2, a, b, z);
    17         printf("%d
    ", t);
    18         for( i=1; i<=t; i++ )
    19         {
    20             printf("%c%c", z[i], i==t?'
    ':' ');
    21         }
    22     }
    23     return 0;
    24 }
    25 
    26 int CommonOrder(int m, int n, char x[], char y[], char z[])
    27 {
    28     int j, i, k;
    29     for( j=0; j<=n; j++ )
    30     {
    31         L[0][j] = 0;
    32     }
    33     for( i=0; i<=m; i++ )
    34     {
    35         L[i][0] = 0;
    36     }
    37     for( i=1; i<=m; i++ )
    38     {
    39         for( j=1; j<=n; j++ )
    40         {
    41             if( x[i-1]==y[j-1] )
    42             {
    43                 L[i][j] = L[i-1][j-1]+1;
    44                 S[i][j] = 1;
    45             }
    46             else if( L[i][j-1]>=L[i-1][j] )
    47             {
    48                 L[i][j] = L[i][j-1];
    49                 S[i][j] = 2;
    50             }
    51             else
    52             {
    53                 L[i][j] = L[i-1][j];
    54                 S[i][j] = 3;
    55             }
    56         }
    57     }
    58     i = m;
    59     j = n;
    60     k = L[m][n];
    61     while( i>=0 && j>=0 )
    62     {
    63         if( S[i][j]==1 )
    64         {
    65             z[k] = x[i-1];
    66             k--;
    67             i--;
    68             j--;
    69         }
    70         else if( S[i][j]==2 )
    71         {
    72             j--;
    73         }
    74         else
    75         {
    76             i--;
    77         }
    78     }
    79     return L[m][n];
    80 }

    算法分析:在算法中,

    第一个for循环的时间性能是O(n);

    第二个for循环的时间性能是O(m);

    第三个循环是两层嵌套的for循环,其时间性能是O(m×n);

    第四个for循环的时间性能是O(k),而k≤min{m,n},所以,算法的时间复杂性是O(m×n)。

  • 相关阅读:
    dapper 批量删除、新增、修改说明
    android 加载assets目录下的静态html文件案例
    webstorm中使用git提交代码时出现unversioned files错误
    windows server 2008 R2 x64 部署.net core 3.1项目
    asp.net core 项目添加nlog日志(loggerFactor.AddNLog 过时处理(.net core 3.1))
    机器学习笔记之一步步教你轻松学主成分分析PCA降维算法
    机器学习笔记之类别特征处理
    机器学习笔记之range, numpy.arange 和 numpy.linspace的区别
    机器学习笔记之Numpy的random函数
    机器学习笔记之矩阵分解 SVD奇异值分解
  • 原文地址:https://www.cnblogs.com/wsy107316/p/10739258.html
Copyright © 2011-2022 走看看