【算法设计与分析】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 


#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 << " "<

你可能感兴趣的:(算法设计与分析)