【算法设计与分析】5、最长公共子序列

/**
* 书本:《算法分析与设计》
* 功能:若给定序列X={x1, x2, ..., xm},则另一序列Z={z1, z2, ..., zk},是X的子序列是指存在一个严格递增下标序列{i1, i2, ..., ik}
*      使得对于所有j=1,2,。。。,k有:zj=xij.给定两个序列X={x1, x2, ... xm}和Y={y1, y2, ..., yn}找出X和Y的最长公共子序列
* 文件:MostLength.cpp
* 时间:2014年11月25日18:23:29
* 作者:cutter_point
*/

#include <iostream>


#define MAXLEN 100

using namespace std;


//这是一个求得最长子序列的长度的函数
//X和Y是两个序列,m和n是长度,c是存放的结果,b是对应的序列序号下之间最长子序列的结构情况
//最长子序列分三种最优子结构
/*
			  {	0						   i=0, j=0
	c[i][j] = {	c[i-1][j-1]+1			   i,j > 0; Xi == Yj 第一类
			  {	max{c[i][j-1], c[i-1][j]}  i,j > 0; Xi != Yj 第二和第三类,大小关系分为两类
*/
void LCSLength(char *x, char *y, char *z, int m, int n, int c[][MAXLEN], int b[][MAXLEN])
{
	int i, j;	//用来标记下标,对应x和y中对应的数
	//首先初始化x和y中第0个匹配的长度为0
	for (i = 1; i <= m; ++i) c[i][0] = 0;
		//c[i][0] = 0;
	//然后初始化x中第0个和y的最长公共子序列长度
	for (i = 1; i <= n; ++i) c[0][i] = 0;

	//int l = 1;	//用来计数第二个序列比较到了第几个数
	//char change = ' ';	//用来记住第一次比较到的字符,如果第二次还得到这个就不重复计数

	//然后把x中每一个元素和y中的每一个元素相匹配
	for (i = 1; i < m; ++i)
	{
		for (j = 1; j < n; ++j)	//y中每一个元素,从上面一个循环中比较到的个数开始比较
		{
			if (x[i] == y[j])//如果对应的元素相等,那么就把长度+1
			{
				c[i][j] = c[i - 1][j - 1] + 1;	//长度是前面的最长度+1,第一类子结构
				
				//l = j+1;		//用来计数第二个序列比较到了第几个数,而且这里应该只计数第一次出现的地方
				z[i] = x[i];
				//change = x[i];	//重新得到一个新的比较计数器
				b[i][j] = 1;	//就是x中第i个和y中第j个的长度中的最长子序列的结构式第一类子结构

				
				//如果找到了和这个一样的子序列,那么就跳出
				//break;
			}
			else if (c[i - 1][j] >= c[i][j - 1])	//去掉这个xi剩下的最长子序列和去掉yj剩下的最长子序列的大小比较
			{
				//如果是最长子序列去掉xi的那个长的话,那么就取这个数
				c[i][j] = c[i - 1][j];
				b[i][j] = 2;	//就是x中第i个和y中第j个的长度中的最长子序列的结构式第二类子结构
			}
			else
			{
				//如果是最长子序列去掉yj的那个长的话,那么就取这个数
				c[i][j] = c[i][j - 1];
				b[i][j] = 3;   //就是x中第i个和y中第j个的长度中的最长子序列的结构式第三类子结构
			}
		}
	}
}


//划分,每次根据上面得到的每层的最优子结构类型划分,来进行不同的操作
//这里i和j分别是是x和y对应的第i个j个元素,x就是比较长的那个序列,b是上面求得的结构层次
/*
			{	0						   i=0, j=0
c[i][j] =	{	c[i-1][j-1]+1			   i,j > 0; Xi == Yj 第一类
			{	max{c[i][j-1], c[i-1][j]}  i,j > 0; Xi != Yj 第二和第三类,大小关系分为两类
*/

//这里参数i和j表示这两个序列拥有的元素个数
void LCS(int i, int j, char *x, int b[MAXLEN][MAXLEN])
{
	if (i == 0 || j == 0) return;	//如果序号都是0,那么就不用匹配了

	if (b[i][j] == 1)	//结构是第一类的时候,说明xi和yj相等
	{
		LCS(i - 1, j - 1, x, b);	//这个就是x和y都已经找到一个相等的子元素了,那就只有剩下的没有输出了
		//输出那个子元素
		cout << x[i] << " ";
	}
	else if (b[i][j] == 2)	//结构是第二类的时候,说明xi比yj大
	{
		LCS(i - 1, j, x, b);	//这是第二种情况,那就把那个大去掉,求剩下的几个的最长子序列
	}
	else				//结构是第三类的时候,说明xi比yj大
	{
		LCS(i, j - 1, x, b);  //这是第三种情况,那就把那个大去掉,求剩下的几个的最长子序列
	}
}


int main()
{
	char x[] = { ' ', 'a', 'x', 'b', 'g', 't', 'c', 'f', 'd', 'g', 'a', 'e', 'f' };
	char y[] = { ' ', 'j', 'a', 'b', 'j', 't', 'j', 'c', 'l', 'd', 'a', 'f' };
	char z[MAXLEN] = {'.'};
	const int m = sizeof(x) / sizeof(x[0]);
	const int n = sizeof(y) / sizeof(y[0]);
	//X和Y是两个序列,m和n是长度,c是存放的结果,b是对应的序列序号下之间最长子序列的结构情况
	int c[MAXLEN][MAXLEN] = {0};
	int b[MAXLEN][MAXLEN] = {0};

	LCSLength(x, y, z, m, n, c, b);
	//输出相应的长度序列
	//cout << "这是什么!" << endl;
	//for (int k = 0; k <= n; ++k)
	//	cout << k << " " << endl;

	for (int i = 1; i < m; ++i)
	{
		cout << i << " "<<endl;
		for (int j = 1; j < n; ++j)
		{
			if (c[i][j] != 0)
			{
				cout << "X序列中前" << i << " 到Y序列中前" << j << " 的公共子序列:" << c[i][j] << " " << endl;
			}
		}
		cout << endl;
	}
	/*
	//求出b的值
	for (int i = 1; i < m; ++i)
	{
		for (int j = 1; j < n; ++j)
			cout << b[i][j] << " ";
		cout << endl;
	}
	
	2 1 3 3
	2 2 2 2
	2 2 1 3

	//求出C
	for (int i = 1; i < m; ++i)
	{
		for (int j = 1; j < n; ++j)
			cout << c[i][j] << " ";
		cout << endl;
	}

	0 1 1 1
	0 1 1 1
	0 1 2 2

	*/

	cout << "最长公共子序列是:" << endl;
	LCS(m-1, n-1, x, b);
	cout << endl;
	
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值