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)。

  • 相关阅读:
    PHP之路——MySql基础操作语句
    PHP简单获取数据库查询结果并返回JSON
    iOS 写入文件保存数据的方式
    触摸事件
    UI基础
    UI基础
    UI基础
    VBS读取txt文档数据查找Excel中单元格数据符合条件的剪切到工作表2中
    vbs查找Excel中的Sheet2工作表是否存在不存在新建
    VBS操作Excel常见方法
  • 原文地址:https://www.cnblogs.com/wsy107316/p/10739258.html
Copyright © 2011-2022 走看看