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

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

前言:

一个给定序列的子序列,就是将给定的序列中零个或多个元素去掉后得到的结果。其形式化定义如下:给定一个序列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]];

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值