动态规划算法——最长公共子序列求法

      给定序列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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值