动态规划-最长公共子序列计算

本文介绍了一种求解最长公共子序列(LCS)问题的经典算法,并提供了详细的递归公式及C++实现代码。通过该算法,可以有效地找出两个序列中最长的共有子序列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 给定两个序列,X={x1,x2,......xm} 和Y={y1,y2,.....yn},求X和Y的最长公共子序列(LCS)的问题。

原理:

对于i=0,1,2....m, X 的第i前缀为Xi={X1,....Xi}, 例如X={A,B,C,D,E,F},则X4={A,B,C,D},假定Z={z1,z2...zk}为上述序列的LCS,则有下面三种情况,

(1)如果xm=yn,则zk=xm=yn,则Zk-1是是Xm-1和Yn-1的一个LCS

(2)如果xm!=yn,则zk!=xm,则Z是是Xm-1和Y的一个LCS

(3)如果xm!=yn,则zk!=yn,则Z是是X和Yn-1的一个LCS

在求X和Y的LCS的过程中,如果xm=yn,我们需要求Xm-1和Yn-1的LCS,并将xm加入到LCS中即可,但是当xm!=yn的时候需要求解Xm-1和Y的LCS和

X和Yn-1的LCS,并选两者较长的一个LCS。


根据上面的分析,可以得到递推公式,c[i][j]表示的是Xi和Yj的LCS的长度

c[i][j]=0, i或者j为0

c[i][j]=c[i-1][j-i]+1,   i,j 大于0,并且xi=yj

c[i][j]=max{c[i-1][j],c[i][j-1]},    i,j 大于0,并且xi!=yj


源码:

#include<iostream>
#include<string>
using namespace std;
#define MAXLENGTH 1000

//计算最长公共子序列
int caculateLcs(int ** count, int** label, char x[], char y[], int xLength, int yLength)
{
	for (int j = 0; j < xLength + 1; j++)
	{
		count[j][0] = 0;
	}
	for (int j = 0; j < yLength + 1; j++)
	{
		count[0][j] = 0;
	}

	for (int i = 1; i <= xLength; i++)
	{
		for (int j = 1; j <= yLength; j++)
		{
			if (x[i - 1] == y[j - 1])
			{
				count[i][j] = count[i - 1][j - 1] + 1;
				label[i - 1][j - 1] = 4;
			}
			else if (count[i - 1][j] >= count[i][j - 1])
			{

				count[i][j] = count[i - 1][j];
				label[i - 1][j - 1] = 5;


			}
			else
			{
				count[i][j] = count[i][j - 1];
				label[i - 1][j - 1] = 1;
			}


		}
	}
	return count[xLength][yLength];
}
//打印最长公共子序列
void printLcs(int** label, char x[], int i, int j)
{
	if (i == 0 || j == 0)
	{
		return;
	}
	if (label[i - 1][j - 1] == 4)
	{
		printLcs(label, x, i - 1, j - 1);
		cout << x[i - 1] << "--";
	}
	else if (label[i - 1][j - 1] == 5)
	{
		printLcs(label, x, i - 1, j);
	}
	else
	{
		printLcs(label, x, i, j - 1);
	}

}
int main()
{
	char x[MAXLENGTH] = { 0 };
	char y[MAXLENGTH] = { 0 };
	cout << "shu ru x: ";
	cin >> x;
	cout << endl;
	cout << "shu ru y: ";
	cin >> y;
	cout << endl;
	int xLength = strlen(x);
	int yLength = strlen(y);
	int** label = new int*[xLength];
	for (int i = 0; i < xLength; i++)
	{
		label[i] = new int[yLength];
	}

	int** count = new int*[xLength + 1];

	for (int i = 0; i < xLength + 1; i++)
	{
		count[i] = new int[yLength + 1];
	}

	int result = caculateLcs(count, label, x, y, xLength, yLength);

	cout << "最长公共子序列长度为:" << result << endl;
	cout << "最长公共子序列为:";
	printLcs(label, x, xLength, yLength);
	cout << endl;
	delete[]label;
	delete[]count;
	system("PAUSE");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值