给定序列X={ X1,X2,....Xn }、Y={ Y1,Y2,...Ym }找出它们的最大子序列Z={ Z1,Z2,...Zk }比如:X={ A,B ,C,B,D,A,B }、Y={ B,D,C,A,B,A },它们的最大子序列
Z={ B,C,B,A}。
c[i][j]表示长度为i的X和长度为j的Y的最长子序列,c[0][j]=0,c[i][0]=0,任一序列与空序列的最长子序列为0。{ X1,X2,.....Xi }、{ Y1,Y2,....Yj },最大子序列长度分2种情况:Xi==Yj,则其长度是{ X1,X2,.....Xi-1 }、{ Y1,Y2,....Yj -1}最长子序列加1,即c[i][j]=c[i-1][j-1]+1,若Xi !=Yj,其长度为{ X1,X2,.....Xi -1}、{ Y1,Y2,....Yj }和
{ X1,X2,.....Xi }、{ Y1,Y2,....Yj -1}中最大的次序列长度,即:c[i][j]=max{ c[i-1][j] ,c[i][j-1] }。
dynamic.h
#pragma once
#include<iostream>
#include<vector>
#include<string>
using namespace std;
class Lseq
{
public:
void insertX(string x);//插入序列X
void insertY(string y);//插入序列Y
void find();//寻找最大子序列
void show();//输出最大子序列
void maxseq(int xi,int yj);
private:
vector<string> X;//输入序列X
vector<string> Y;//输入序列Y
vector<string>Z;//最长公共子序列
vector<vector<int> > c;//公共子序列的长度
vector<vector<int> >path;//记录路径
};
dynamic.cpp
#include "stdafx.h"
#include"dynamic.h"
#include<iostream>
#include<vector>
#include<string>
using namespace std;
void Lseq::insertX(string x)
{
X.push_back(x);
}
void Lseq::insertY(string y)
{
Y.push_back(y);
}
void Lseq::find()
{
//分配c、path大小
int nx=X.size();
int ny=Y.size();
c.resize(nx+1);
path.resize(nx);
for(int i=0;i<c.size();i++)
{
c[i].resize(ny+1);
if(i<nx)
path[i].resize(ny);
}
for(int i=0;i<c.size();i++)
{
c[i][0]=0; //Y长度为0,则公共的子序列长度为0
}
for(int i=0;i<ny+1;i++)
{
c[0][i]=0;//X的长度为0,则公共的子序列长度为0
}
for(int i=0;i<nx;i++)
for(int j=0;j<ny;j++)
{
if(X[i]==Y[j])
{
c[i+1][j+1]=c[i][j]+1;
path[i][j]=0;//相等标记
}
else if(c[i+1][j]>c[i][j+1])
{
c[i+1][j+1]=c[i+1][j];
path[i][j]=1;
}
else
{
c[i+1][j+1]=c[i][j+1];
path[i][j]=2;
}
}
}
void Lseq::show()
{
find();
int nx=X.size();
int ny=Y.size();
cout<<"最长子序列长度:"<<c[nx][ny]<<endl;
cout<<"最长子序列为:";
maxseq(nx-1,ny-1);//采用递归倒序的需找最长子序列
cout<<endl;
}
void Lseq::maxseq(int xi,int yj)
{
if((xi<0)||(yj<0))
return;
if(path[xi][yj]==0)
{
maxseq(xi-1,yj-1);
cout<<X[xi]<<" ";
}
else if(path[xi][yj]==1)
maxseq(xi,yj-1);
else
maxseq(xi-1,yj);
}
Algorithm-dynamic2.cpp
// Algorithm-dynamic2.cpp : 定义控制台应用程序的入口点。
//
//实现最长公共序列
#include "stdafx.h"
#include"dynamic.h"
#include<iostream>
#include<vector>
#include<string>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
Lseq s;
//输入序列X
s.insertX("A");
s.insertX("B");
s.insertX("C");
s.insertX("B");
s.insertX("D");
s.insertX("A");
s.insertX("B");
//输入序列Y
s.insertY("B");
s.insertY("D");
s.insertY("C");
s.insertY("A");
s.insertY("B");
s.insertY("A");
//输出最长子序列长度和最长子序列
s.show();
return 0;
}
补充:对函数void maxseq(int xi,int yj);的说明,其主要功能是用于寻找最大的子序列。采用逆序查找,例中path 矩阵为:
X={ A,B ,C,B,D,A,B }、Y={ B,D,C,A,B,A }。开始:
(1)xi=6,yj=5;判断path[6][5]==0?即X[6]与Y[5]是否相等,不相等。path[6][5]=2即xi=5,yj=5 这表明c[xi][yj]=c[xi-1][yj]
(2)在X={ A,B ,C,B,D,A }、Y={ B,D,C,A,B,A }中查找最大序列,path[5][5]==0,所以X[5]与Y[5]相等,X[5]为最大子序列中的一个,X[5]=A压入栈中。xi=xi-1=4,yj=yj-1=4
(3)X={ A,B ,C,B,D }、Y={ B,D,C,A,B }中查找最大序列,path[4][4]==2,xi=xi-1=3,yj=yj=4
(4)X={ A,B ,C,B }、Y={ B,D,C,A,B }中查找最大序列,path[3][4]==0,X[3]为最大子序列中一个,X[3]=B压入栈中,xi=xi-1=2,yj=yj-1=3
(5)X={ A,B ,C }、Y={ B,D,C,A }中查找最大序列,path[2][3]==1,xi=xi=2,yj=yj-1=2
(6)X={ A,B ,C }、Y={ B,D,C }中查找最大序列,path[2][2]==0,X[2]为最大子序列中一个,X[2]=C压入栈中,xi=xi-1=1,yj=yj-1=1;
(7)X={ A,B }、Y={ B,D }中查找最大序列,path[1][1]==1,xi=xi=1,yj=yj-1=0;
(8)X={ A,B }、Y={ B }中查找最大序列,path[1][0]==0,X[1]为最大子序列中一个,X[1]=B压入栈中,xi=xi-1=0,yj=yj-1=-1;
(9)yj<0返回,则最大子序列查找到,输出:B C B A