问题描述
输入:
输出:
Z=X和Y的最长公共子序列
说明:
如果:
结构分析
我们将一个序列如
我们将
我们将
我们看一下如下的关系:
我们假设
我们就可以知道
(1)当
(2)当
(3)当
建立递推方程
我们定
我们有以下的递推方程:
(1)当
(2)当
(2)当
自底向上计算LCS
我们现在有一个二维表,抽取其中的
我们在知道
我们取一个
画出如图的二维表,我们目的是求出最右下角的
根据上面的递推方程(1)我们得到如下的数组的值都为
接下来我们就可以由以上已知的部分依次得到最长公共序列的个数!
比如:
现在我们根据上面的方法可以得到相应最长公共子序列的个数了,那么怎样得到这个最长公共子序列呢?
我们只需要从这个二维表的最右下角向左上角回溯即可!详细看代码:
int num=0;
int i=xLen;
int j=yLen;
//回溯获得最长子序列
while(i!=0&&j!=0){
if(c[i][j]!=c[i-1][j]){
z[++num]=x[i];
j--;
i--;
while(c[i][j]==c[i][j-1]) j--;
}else{
i--;
}
}
编程实现
如果觉得上面说的太过于啰嗦,或者我表述的并不是很清晰,那么我们就直接看代码吧!
#include<iostream>
#include<cstring>
#define MAX_LEN 100
using namespace std;
/**
* @author zjq~
* @time 2017/07/08
* @func 动态规划求解最长公共子序列问题
*/
char x[MAX_LEN]; //两个子序列
char y[MAX_LEN];
int xLen=0; //两个子序列的长度
int yLen=0;
char z[MAX_LEN]; //保存最长公共子序列
int c[MAX_LEN][MAX_LEN]; //记录LCS[i][j] 的个数
void getLCS() {
//构造二维表
for(int i=0; i<=xLen; i++) {
for(int j=0; j<=yLen; j++) {
if(i==0||j==0) {
c[i][j]=0;
} else if(i>0&&&j>0&&x[i]==y[j]) {
c[i][j]=c[i-1][j-1]+1;
} else {
c[i][j]=c[i-1][j]>c[i][j-1]?c[i-1][j]:c[i][j-1];
}
}
}
int num=0;
int i=xLen;
int j=yLen;
//回溯获得最长子序列
while(i!=0&&j!=0){
if(c[i][j]!=c[i-1][j]){
z[++num]=x[i];
j--;
i--;
while(c[i][j]==c[i][j-1]) j--;
}else{
i--;
}
}
}
int main() {
cin>>xLen; //下标从 i=1 开始
for(int i=1; i<=xLen; i++) {
cin>>x[i];
}
cin>>yLen;
for(int i=1; i<=yLen; i++) {
cin>>y[i];
}
getLCS(); //获得最长公共子序列
cout<<"最长公共子序列包含元素个数为:"<<c[xLen][yLen]<<endl;
cout<<"最长公共子序列为:";
for(int i=c[xLen][yLen];i>0;i--){
cout<<z[i]<<" ";
}
cout<<endl;
}
运行结果截图:
最后
去九度OJ提交一下看看你的代码是否正确吧!
http://ac.jobdu.com/problem.php?pid=1042
注意一下两点:
使用gets
加上头文件#include<cstdio>
OJ上面的题目需要测试多组数据,注意使用while(gets(x)){}
来源:CSDN
作者:片刻清夏
链接:https://blog.csdn.net/zjq_1314520/article/details/74849442