动态规划之最长公共子序列问题
前言:
一个给定序列的子序列,就是将给定的序列中零个或多个元素去掉后得到的结果。其形式化定义如下:给定一个序列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][n]开始并按箭头方向进行追踪下去即可。当在表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]];
}