最长公共子序列
序列X={x1,x2,x3,...xn}
序列Y={y1,y2,y3,...yn}
最长公共子序列的含义是既是X的子序列,也是Y的子序列,并且按照严格递增的下标,这些子序列中长度最长的子序列就是最长公共子序列
穷举搜索法是最容易想到的,求出X的所有子序列,并且判断是否同样为Y的子序列,然后输出最长公共子序列。
事实上
最长公共子序列问题有最优子结构性质
设序列和的最长公共子序列为
若Xn==Ym,则Zk=Xn==Ym,且Z(k-1)是X(n-1)和Y(m-1)的最长公共子序列
若Xn!=Ym,且Zk!=Ym,则Z是X(n-1)和Y的最长公共子序列
若Xn!=Ym,且Zk!=Xn,则Z是X和Y(n-1)的最长公共子序列
定义数组,表示序列的前n个元素和序列的前m个元素的最长公共子序列的长度。
定义数组,记录的数值由哪一个子问题得到的。
具体讲解请看《算法导论》
方向表就是为了输出最长子序列的时候找到是得到该最优解的子问题。
#include<iostream>
#include<random>
#include<time.h>
using namespace std;
const int n=7;
const int m=6;
int main()
{
void func(intc[n+1][m+1],int b[n+1][m+1],char X[],int i,int j);
srand((unsigned)time(NULL));
char X[]="#ABCBDAB";
char Y[]="#BDCABA";
int c[n+1][m+1]={0};
int b[n+1][m+1]={0};
int i=0,j=0;
c[0][0]=0;
for(i=1;i<=n;i++)
{
c[i][0]=0;
}
for(i=1;i<m;i++)
{
c[0][i]=0;
}
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(X[i]==Y[j])
{
c[i][j]=c[i-1][j-1]+1;
b[i][j]=1;
}
else if(c[i-1][j]>=c[i][j-1])
{
c[i][j]=c[i-1][j];
b[i][j]=2;
}
else
{
c[i][j]=c[i][j-1];
b[i][j]=3;
}
}
}
cout<<"输出子序列长度表"<<endl;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
cout<<c[i][j]<<" ";
}
cout<<endl;
}
cout<<"输出字符方向表:"<<endl;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
cout<<b[i][j]<<" ";
}
cout<<endl;
}
cout<<"输出最长子序列:"<<endl;
func(c,b,X,n,m);
cout<<endl;
cout<<"子序列长度为"<<c[n][m]<<'!'<<endl;
return 0;
}
void func(int c[n+1][m+1],int b[n+1][m+1],charX[],int i,intj)
{
if(i<1||j<1)
{
return;
}
if(b[i][j]==1)
{
func(c,b,X,i-1,j-1);
cout<<X[i]<<" ";
}
else if(b[i][j]==2)
{
func(c,b,X,i-1,j);
}
else
{
func(c,b,X,i,j-1);
}
}