实验四 动态规划算法--最长公共子序列问题

动态规划算法解LCS问题

1 最长公共子序列的结构

   最长公共子序列的结构有如下表示:

   设序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的一个最长公共子序列Z=<z1, z2, …, zk>,则:

   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的最长公共子序列;

   其中Xm-1=<x1, x2, …, xm-1>,Yn-1=<y1, y2, …, yn-1>,Zk-1=<z1, z2, …, zk-1>。

2 子问题的递归结构

   由最长公共子序列问题的最优子结构性质可知,要找出Xm=<x1, x2, …, xm>和Yn=<y1, y2, …, yn>的最长公共子序列,可按如下方式递归的进行:

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

   ·当xm≠yn时,必须解两个子问题,即找出Xm-1和Y的一个最长公共子序列及X和Yn-1的一个最长公共子序列。这两个公共子序列中较长者即为X和Y的一个最长公共子序列。

   由此递归结构容易看到最长公共子序列问题具有子问题重叠性质。例如,在计算X和Y的最长公共子序列时,可能要计算出X和Yn-1以及Xm-1和Y的最长公共子序列。而这两个子问题都包含一个公共子问题,即计算Xm-1和Yn-1的最长公共子序列。

   与矩阵乘积最优计算次序问题类似,我们来建立子问题的最优值的递归关系。用c[i,j]记录序列Xi和Yj的最长公共子序列的长度,其中Xi=<x1, x2, …, xi>,Yj=<y1, y2, …, yj>。当i = 0或j = 0时,空序列是Xi和Yj的最长公共子序列,故c[i,j] = 0。其他情况下,可得递归关系如下所示:

26548237_13511685897t6t.jpg

3 计算最优值

   直接利用上节节末的递归式,我们将很容易就能写出一个计算c[i,j]的递归算法,但其计算时间是随输入长度指数增长的。由于在所考虑的子问题空间中,总共只有O(m*n)个不同的子问题,因此,用动态规划算法自底向上地计算最优值能提高算法的效率。

   计算最长公共子序列长度的动态规划算法LCS_Length(X,Y),以序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>作为输入。输出两个数组c[0..m ,0..n]和b[1..m ,1..n]。其中c[i,j]存储Xi与Yj的最长公共子序列的长度,b[i,j]记录指示c[i,j]的值是由哪一个子问题的解达到的,这在构造最长公共子序列时要用到。最后,X和Y的最长公共子序列的长度记录于c[m,n]中。

   1:  #include<iostream>
   2:  #include<stdlib.h>
   3:  #include<string.h> 
   4:  using namespace std;
   5:  const int strlens=15;
   6:  int b[strlens][strlens],c[strlens][strlens];
   7:  void LCSLength(string x,string y){
   8:      int m=x.length(),n=y.length();
   9:      for(int i=1;i<=m;i++)
  10:          for(int j=1;j<=n;j++)
  11:          {
  12:              if(x[i]==y[j])
  13:              {
  14:                  c[i][j]=c[i-1][j-1]+1;
  15:                  b[i][j]=1; 
  16:              }
  17:              else if(c[i-1][j]>=c[i][j-1])
  18:              {
  19:                  c[i][j]=c[i-1][j];
  20:                  b[i][j]=2;         
  21:              }
  22:              else
  23:              {
  24:                  c[i][j]=c[i][j-1];
  25:                  b[i][j]=3;
  26:              }         
  27:          }
  28:  } 
  29:  void LCS(int i,int j,string x){
  30:      if(i==0||j==0) return;
  31:      if(b[i][j]==1)
  32:      {
  33:          LCS(i-1,j-1,x);
  34:          printf("%c",x[i]);
  35:      }
  36:      else if(b[i][j]==2)
  37:          LCS(i-1,j,x);
  38:      else 
  39:          LCS(i,j-1,x);
  40:  } 
  41:  int main(){
  42:      string x="AFJGGFJGEJVODF",y="FFOEJFOEJFODJF";
  43:      memset(c,0,sizeof(c));
  44:      memset(b,0,sizeof(b));
  45:      LCSLength(x,y);
  46:      LCS(14,14,x);
  47:      cout<<endl;
  48:  }

转载于:https://www.cnblogs.com/ZJUT-jiangnan/archive/2013/05/31/3110010.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值