给定两个序列
例如:
对于此问题,可以采用暴力求解的方式来比对,即穷举出X的所有子序列,用每个子序列与y做一 一比较。假如X序列共有m个元素,对每个元素可以决定选或不选,则X的子序列个数共有
前几篇博文已介绍了采用动态规划的方法解决装配线问题及钢铁切割问题,它们都满足了两个条件:1.具有最优子结构的特征 2.子问题重叠。
首先定义前缀
则有以下定理:
假如序列
1.如果
2.如果
2.如果
上述定理即为要求得X和Y的LCS,可以根据
由以上分析:令c[i][j]为表示序列
用数组c[m][n]保存子序列
从上到下,从做到右:复杂度为
1.可以采用b[i][j]中记录的值,依次倒序输出,从b[7][6]开始倒序输出。也可以用递归的方法,从底层开始,正序输出;
2.不用b[i][j],即改进版,由于c[i][j]是由c[i-1][j-1]、c[i-1][j]、c[i][j-1],可以根据它们的关系,判断出方向;运行时间都为
求
/************************************************************************
CSDN 勿在浮沙筑高台
http://blog.csdn.net/luoshixian099
算法导论--动态规划(最长公共子序列)
2015年6月5日
main.cpp
************************************************************************/
#include<iostream>
using namespace std;
int b[8][7]={0},c[8][7]={0};
void Lcs_Length(char *X,char *Y) // 遍历序列X和Y,自底向上计算出c[i][j]
{
for(int i=1;i<=7;i++)
for(int j=1;j<=6;j++)
{
if(X[i] == Y[j])
{
c[i][j] = c[i-1][j-1]+1;
b[i][j] = 2; //左上方
}
else if(c[i-1][j] >= c[i][j-1])
{
c[i][j] = c[i-1][j];
b[i][j]=1; //上方
}
else
{
c[i][j] = c[i][j-1];
b[i][j] = 3; //左方
}
}
}
void Print_Lcs(int b[][7],char *X,int i,int j) //采用b[i][j]递归输出LCS
{
if(i == 0 || j == 0)
return ;
if(b[i][j] == 2)
{
Print_Lcs(b,X,i-1,j-1);
cout<<" "<<X[i];
}
else if(b[i][j] == 1)
Print_Lcs(b,X,i-1,j);
else
Print_Lcs(b,X,i,j-1);
}
void Print_Lcs(char *X,char *Y,int i,int j)//不用b[i][j],递归输出LCS
{
if(i == 0 || j == 0)
return ;
if(X[i] == Y[j])
{
Print_Lcs(X,Y,i-1,j-1);
cout<<" "<<X[i];
}
else if(c[i-1][j] >= c[i][j-1])
Print_Lcs(X,Y,i-1,j);
else
Print_Lcs(X,Y,i,j-1);
}
int main()
{
char X[]={‘ ‘,‘A‘,‘B‘,‘C‘,‘B‘,‘D‘,‘A‘,‘B‘};
char Y[]={‘ ‘,‘B‘,‘D‘,‘C‘,‘A‘,‘B‘,‘A‘};
Lcs_Length(X,Y);
for(int i=0;i<8;i++) //输出数组内的值
{
for(int j=0;j<7;j++)
cout<<" "<<c[i][j];
cout<<endl;
}
cout<<endl;
Print_Lcs(b,X,7,6); //输出LCS
cout<<endl;
Print_Lcs(X,Y,7,6); //改进的版本
cout<<endl;
return 0;
}
原文地址:http://blog.csdn.net/luoshixian099/article/details/46374243