您的位置:首页 > 其它

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

2014-03-09 16:23 393 查看
动态规划之最长公共子序列问题
前言:
一个给定序列的子序列,就是将给定的序列中零个或多个元素去掉后得到的结果。其形式化定义如下:给定一个序列X={x1,x2,x3,x4….Xn},另一个序列Z={z1,z2,z3,z4……Zn}满足如下条件时称为X的子序列,即存在一个严格递增的X下表序列(i1,i2…….ik),对所有j=1,2,3,…..k满足xi=zj例如Z=<B,C,D,B>是X=<A,B,C,B,D,A,B>的子序列对应的下标的序列为<2,3,5,7>
给定两个序列X,Y,如果Z即使X的序列又是Y的子序列我们称X和Y的公共子序列
问题描述:
给定两个序列X{x1,x2,x3,……xm}和Y={y1,y2,y3…..yn}求X和Y长度最长的公共最长子序列 简称LCS问题
问题的解决:
步骤一:刻画最长公共子序列的特征:
前缀的严格定义:
给定一个序列X=<x1,x2,x3….xm>对i=0,1,2…..m,定义X的第i前缀为Xi=<x1,x2,x3…..xi>例如:X<A,B,C,B,D,B,A>则X4=<A,B,C,B>,X0为空串
LCS的最优子结构:
X=<x1,x2,…,xm> 和 Y=<y1,y2,…,yn>为两个序列的,Z=<z1,z2,z3…zk>为X和Y的任意LCS
如果xm= yn,那么zk=xm= yn而且Zk-1是Xm-1和 Yn-1的一个LCS
如果xm≠ yn,那么zk≠xm蕴含Z是Xm-1和 Y的一个LCS
如果xm≠ yn,那么zk≠yn蕴含Z是X和 Yn-1的一个LCS



v 步骤2:一个递归解
c[i,j]为序列Xi 和Yj一个LCS的长度



v 步骤3:一个递归解计算LCS长度





步骤4构造LCS
我们可以利用LCS_LENGTH返回的表b快速构造X<x1,x2,x3….xm>
和Y=<y1,y2….yn>只需简单的从b[m]
开始并按箭头方向进行追踪下去即可。当在表b[i][j]中遇到一个左上箭头意味着xi=yj是LCS的一个元素
伪代码:
PRINT_LCS(b,X,i,j)
1 if i==0orj==0
2 return
3if b[i,j]==”左上箭头”
4 PRINT_LCS(b,X,i-1,j-1)
5 print xi
6 elseif n[I,j]==”上箭头”
7 PRINT_LCS(b,X,i-1,j-1)
8else PRINT_LCS(b,X,i,j-1)
--------------------------------C++对以上算法的实------------------------------------
#define MaxNumber 20

char b[MaxNumber][MaxNumber];

static int Mem[20];

int num=0;

void LCS_LENGTH(char X[],char Y[],int Xlength,int Ylength)

{

int m=Xlength;

int n=Ylength;

int c[MaxNumber][MaxNumber];

for(int i=0;i<=m;i++)

c[i][0]=0;

for(int j=0;j<=n;j++)

c[0][j]=0;

for(int i=1;i<=m;i++)

{

for(int j=1;j<=n;j++)

{

if(X[i]==Y[j])

{

c[i][j]=c[i-1][j-1]+1;

b[i][j]='!';

}

else if(c[i-1][j]>=c[i][j-1])

{

c[i][j]=c[i-1][j];

b[i][j]='@';

}

else

{

c[i][j]=c[i][j-1];

b[i][j]='#';

}

}

}

}

int PRINT_LCS(char b[MaxNumber][MaxNumber],char X[],int Xlength,int Ylength)

{

if(Xlength==0||Ylength==0)

return 1;

if(b[Xlength][Ylength]=='!')

{

PRINT_LCS(b,X,Xlength-1,Ylength-1);

Mem[num++]=Xlength;

cout<<"X-"<<Xlength<<"("<<X[Xlength]<<")"<<",";

}

else if(b[Xlength][Ylength]=='@')

{

PRINT_LCS(b,X,Xlength-1,Ylength);

}

else PRINT_LCS(b,X,Xlength,Ylength-1);

}

void main()

{

int xlength,ylength;

char X[]={'0','A','F','C','B','D','A','B','D','G','T'};

char Y[]={'0','A','B','C','A','B','A','G','R','T'};

xlength=sizeof(X)/sizeof(char);

ylength=sizeof(Y)/sizeof(char);

LCS_LENGTH(X,Y,xlength-1,ylength-1);

PRINT_LCS(b,X,xlength-1,ylength-1);

cout<<endl;

for(int i=1;i<=xlength;i++)

cout<<X[i];

cout<<endl;

for(int i=1;i<=ylength;i++)

cout<<Y[i];

cout<<endl;

cout<<"最长公共子序列:";

for(int i=0;i<num;i++)

cout<<X[Mem[i]];

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: