最长公共子序列
Posted batcaesar-mmm
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最长公共子序列相关的知识,希望对你有一定的参考价值。
问题描述:
设集合x,集合y,集合元素若干,求x和y的最长公共子序列。(子序列:给定一个序列,该序列中删去若干元素后得到的序列)
备注:
- 编程语言:c++
- 编译器:Code::Blocks 16.01
- 操作系统:windows 10
源代码:
//最长公共子序列
/*测试数据
7 6
A B C B D A B
B D C A B A
*/
7 6
A B C B D A B
B D C A B A
*/
#include<iostream>
using namespace std;
//计算最长公共子序列长度的动态规划算法LSCLength
void LCSLength(int m,int n,char *x,char *y,int **c,int **b)
{
int i,j;
for(i=1; i <= m; i++)
c[i][0] = 0;
for(i=1; i <= n;i++)
c[0][i] = 0;
for(i=1; i <= m; i++)
for(j=1; j <= m; j++)
{
if(x[i] == y[j])
{
c[i][j] = c[i-1][j-1]+1; //子问题1:c[i][j]值等于斜上方的长度加1
b[i][j] = 1;
}
else if(c[i-1][j] >= c[i][j-1])
{
c[i][j] = c[i-1][j]; //子问题2:c[i][j]值等于上面的长度
b[i][j] = 2;
}
else
{
c[i][j] = c[i][j-1]; //子问题3:c[i][j]值等于左面的长度
b[i][j] = 3;
}
}
}
void LCSLength(int m,int n,char *x,char *y,int **c,int **b)
{
int i,j;
for(i=1; i <= m; i++)
c[i][0] = 0;
for(i=1; i <= n;i++)
c[0][i] = 0;
for(i=1; i <= m; i++)
for(j=1; j <= m; j++)
{
if(x[i] == y[j])
{
c[i][j] = c[i-1][j-1]+1; //子问题1:c[i][j]值等于斜上方的长度加1
b[i][j] = 1;
}
else if(c[i-1][j] >= c[i][j-1])
{
c[i][j] = c[i-1][j]; //子问题2:c[i][j]值等于上面的长度
b[i][j] = 2;
}
else
{
c[i][j] = c[i][j-1]; //子问题3:c[i][j]值等于左面的长度
b[i][j] = 3;
}
}
}
//LCS实现根据b的内容打印出x和y最长公共子序列
void LCS(int i,int j,char *x,int **b)
{
if(i==0 || j==0)
return;
if(b[i][j] == 1)
{
LCS(i-1,j-1,x,b);
cout<<x[i];
}
else if(b[i][j] == 2)
LCS(i-1,j,x,b);
else
LCS(i,j-1,x,b);
}
void LCS(int i,int j,char *x,int **b)
{
if(i==0 || j==0)
return;
if(b[i][j] == 1)
{
LCS(i-1,j-1,x,b);
cout<<x[i];
}
else if(b[i][j] == 2)
LCS(i-1,j,x,b);
else
LCS(i,j-1,x,b);
}
int main()
{
int mm,nn; //mm:xx集合元素个数 yy集合元素个数
char *xx,*yy;
int **cc,**bb;
{
int mm,nn; //mm:xx集合元素个数 yy集合元素个数
char *xx,*yy;
int **cc,**bb;
cout<<"分别输入x和y集合元素个数:"<<endl;
cin>>mm>>nn;
cin>>mm>>nn;
xx = new char[mm+1]; //xx集合
yy = new char[nn+1]; //yy集合
//输入数据
cout<<"x集合元素:"<<endl;
for(int r=1;r<=mm;r++)
cin>>xx[r];
cout<<"y集合元素:"<<endl;
for(int r=1;r<=nn;r++)
cin>>yy[r];
yy = new char[nn+1]; //yy集合
//输入数据
cout<<"x集合元素:"<<endl;
for(int r=1;r<=mm;r++)
cin>>xx[r];
cout<<"y集合元素:"<<endl;
for(int r=1;r<=nn;r++)
cin>>yy[r];
//创建动态二维数组
cc = new int*[mm+1]; //cc[i][j]存储xx和yy的最长公共子序列的长度
bb = new int*[mm+1]; //bb[i][j]记录cc[i][j]的值是由哪个子问题得到的
/*子问题:
1--cc[i][j] = cc[i-1][j-1]+1 (斜上方的长度加1)
2--cc[i][j] = cc[i-1][j] (等于上面的长度)
3--cc[i][j] = cc[i][j-1] (等于左边的长度)
*/
for(int i=0;i<=mm; i++)
{
cc[i] = new int[nn];
bb[i] = new int[nn];
}
cc = new int*[mm+1]; //cc[i][j]存储xx和yy的最长公共子序列的长度
bb = new int*[mm+1]; //bb[i][j]记录cc[i][j]的值是由哪个子问题得到的
/*子问题:
1--cc[i][j] = cc[i-1][j-1]+1 (斜上方的长度加1)
2--cc[i][j] = cc[i-1][j] (等于上面的长度)
3--cc[i][j] = cc[i][j-1] (等于左边的长度)
*/
for(int i=0;i<=mm; i++)
{
cc[i] = new int[nn];
bb[i] = new int[nn];
}
//赋初值
for(int j=0;j<=mm;j++)
{
for(int k=0;k<=nn;k++)
{
cc[j][k]=-1;
bb[j][k]=-1;
}
}
for(int j=0;j<=mm;j++)
{
for(int k=0;k<=nn;k++)
{
cc[j][k]=-1;
bb[j][k]=-1;
}
}
cout<<endl;
LCSLength(mm,nn,xx,yy,cc,bb);
LCSLength(mm,nn,xx,yy,cc,bb);
//输出二维数组
cout<<"c[i][j]存储x和y的最长公共子序列的长度:"<<endl;
for(int j=0;j<=mm;j++) //输出cc[i][j],cc[i][j]存储xx和yy的最长公共子序列的长度
{
for(int k=0;k<=nn;k++)
cout<<cc[j][k]<<" ";
cout<<endl;
}
cout<<endl;
cout<<"c[i][j]存储x和y的最长公共子序列的长度:"<<endl;
for(int j=0;j<=mm;j++) //输出cc[i][j],cc[i][j]存储xx和yy的最长公共子序列的长度
{
for(int k=0;k<=nn;k++)
cout<<cc[j][k]<<" ";
cout<<endl;
}
cout<<endl;
cout<<"b[i][j]记录c[i][j]的值是由哪个子问题得到的:"<<endl;
cout<<"1--cc[i][j] = cc[i-1][j-1]+1 (斜上方的长度加1)"<<endl;
cout<<"2--cc[i][j] = cc[i-1][j] (等于上面的长度)"<<endl;
cout<<"3--cc[i][j] = cc[i][j-1] (等于左边的长度)"<<endl;
for(int j=0;j<=mm;j++) //输出bb[i][j],bb[i][j]记录cc[i][j]的值是由哪个子问题得到的
{
for(int k=0;k<=nn;k++)
cout<<bb[j][k]<<" ";
cout<<endl;
}
cout<<"1--cc[i][j] = cc[i-1][j-1]+1 (斜上方的长度加1)"<<endl;
cout<<"2--cc[i][j] = cc[i-1][j] (等于上面的长度)"<<endl;
cout<<"3--cc[i][j] = cc[i][j-1] (等于左边的长度)"<<endl;
for(int j=0;j<=mm;j++) //输出bb[i][j],bb[i][j]记录cc[i][j]的值是由哪个子问题得到的
{
for(int k=0;k<=nn;k++)
cout<<bb[j][k]<<" ";
cout<<endl;
}
cout<<endl;
cout<<"最长公共子序列:";
LCS(mm,nn,xx,bb);
cout<<endl;
cout<<"最长公共子序列:";
LCS(mm,nn,xx,bb);
cout<<endl;
//释放空间
delete[] xx;
delete[] yy;
delete[] xx;
delete[] yy;
for(int i=0;i<=nn;i++)
{
delete[] cc[i];
delete[] bb[i];
}
delete[] cc;
delete[] bb;
{
delete[] cc[i];
delete[] bb[i];
}
delete[] cc;
delete[] bb;
return 0;
}
}
运行界面:
以上是关于最长公共子序列的主要内容,如果未能解决你的问题,请参考以下文章
最长递增子序列 && 最大子序列最长递增子序列最长公共子串最长公共子序列字符串编辑距离