动态规划之最长公共子序列

来源:互联网 发布:淘宝客服搞笑评价回复 编辑:程序博客网 时间:2024/05/04 13:35

背景:

        对于两个给定的序列X ={A,B,C,D,A,B},Y={B,D,C,A,B,A},例如{B,C,D,A}是他们的最长公共子序列,但并不是唯一的最长公共子序列。比如说{B,D,A,B}

       但该动态规划算法着重于分析如何求出一个最长公共子序列,至于求出所有最长公共子序列,或者是多个给定的序列求最长公共子序列还需有待研究!

分析:

        动态规划算法的特征总是先由大到小的分析出最优子结构,再通过递归自下到上的得出所得解。

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

         从整体开始分析,即从尾部往前推

        1.若xm=yn,则zk=xm=yn,且Z k-1是Xm-1和Yn-1的最长公共子序列,这样便降低问题规模,达到了用递归求解的目的

        2.若xm!=yn且zk!=xm,则Z是Xm-1和Y n的最长公共子序列

        3.若xm!=yn且zk!=yn,则Z是Xm和Y n-1的最长公共子序列


建立问题模型:

      1.假设用c[i][j]表示Xi和Yj的最长公共子序列的长度,Xi={x1,x2.....xi} Yj={y1,y2......yj}

      2.边界条件考虑,i=0或者j=0时,c[i][j]=0

        所以

                              0                                   i=0或者j=0

               c[i][j]=  c[i-1][j-1]+1                   i,j>0;xi=yj

                          Max{c[i][j-1],c[i-1][j]}         i,j>0;xi!=yj

性能分析:

      每一次x[i]和y[j]的比较就降低一次问题规模,总共比较了mxn次,所以时间复杂度为O(nm).。相对于一般的穷举算法,即列举出X 的所有子序列共有2的n次方种,和Y序列一个个的进行比对,时间复杂度为O(2n),相比复杂度从指数规模降低到了平方级规模。


#include<iostream>using namespace std;#define MAX 20void LCSLength(int m,int n,char *x,char *y,int c[][MAX],int b[][MAX]){int i,j;for( i=1;i<=m;i++) c[i][0]=0;   //只有x或y的情况下,c[i][j]都为0for(i=1;i<=n;i++) c[0][i]=0;  for( i=1;i<=m;i++)for(j=1;j<=n;j++){if(x[i]==y[j]){c[i][j]=c[i-1][j-1]+1;   //加上这个位置的字符b[i][j]=1;}else if(c[i-1][j]>=c[i][j-1]){c[i][j]=c[i-1][j];b[i][j]=2;}else {c[i][j]=c[i][j-1];b[i][j]=3;}cout<<"c["<<i<<"]["<<j<<"]"<<c[i][j]<<"  b["<<i<<"]["<<j<<"]"<<b[i][j]<<endl;}}void LCS(int i,int j,char *x,int b[][MAX]){if(i==0||j==0)return ;if(b[i][j]==1){LCS(i-1,j-1,x,b);cout<<x[i];}else if(b[i][j]==2)LCS(i-1,j,x,b);else LCS(i,j-1,x,b);}void InitSequence(int n,char *s){cout<<"请输入"<<n<<"个字符序列"<<endl;for(int i=1;i<=n;i++)cin>>s[i];}int main(){int m,n;char x[MAX],y[MAX];int c[MAX][MAX],b[MAX][MAX];while(scanf("%d %d",&m,&n)==2){InitSequence(m,x);InitSequence(n,y);LCSLength(m,n,x,y,c,b);LCS(m,n,x,b);}return 0;}


0 0