最大公共子序列问题

本文详细解析了动态规划求解最大公共子序列问题中的状态转移,通过四个关键步骤说明了dp[i][j]的计算过程,强调了特殊情况下的dp[i-1][j]和dp[i][j-1]的使用。实例代码展示了如何在C++中实现。

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

 

 状态转移图

 分析

1.a[i]不是公共子序列,b[j]是                           dp[i][j]=max(...,dp[i-1][j]);

这里不能简单的认为dp[i-1][j]就是表示a[i]不在lcs中,b[j]在lcs中

因为dp[i-1][j]表示的意义是:a[1...i-1]和b[1...j]的最大公共子序列lcs

那么他就包含两种情况

    

所以他不能完全等价的用dp[i-1][j]来解释,这里包含两种情况。能够使用dp[i-1][j]的原因是:我们要求的是最值,求最值的特点是允许重复,不允许遗漏。运用dp[i-1][j]来表示虽然重复了b[j]不在lcs中,即dp[i-1][j-1]的情况,但是却保证了能够求出一个最值。

2.b[j]不是公共子序列,a[i]在                             dp[i][j]=max(...,dp[i][j-1]);

分析同上

3.a[i]和b[j]都不在公共子序列中                          dp[i][j]=max(...,dp[i-1][j-1]);

因为1.2步会重复比较两次dp[i-1][j-1]的值,所以可以省略

4.a[i]和b[j]在公共子序列中                                 dp[i][j]=dp[i-1][j-1]+1;

dp[i][j]=dp[i-1][j-1]+1一定是≥max(dp[i-1][j],dp[i][j-1]);

因为他们都是从dp[i-1][j-1]递推而来,至多+1

 

#include <iostream>
#include <algorithm>
using namespace std;
int a[1005];
int b[1005];
int dp[1005][1005];		//dp[i][j],a数组的前i个元素与b数组的前j个元素的最大公共子序列
int main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 1;i <= n;i++)				//输入子序列a
		cin >> a[i];
	for (int i = 1;i <= m;i++)
		cin >> b[i];
	int ans = -1;
	for (int i = 1;i <= n;i++)
	{
		dp[0][i] = dp[i][0] = 0;			//两种不可能的情况
		for (int j = 1;j <= n;j++)
		{	if(a[i]==b[j])
				dp[i][j] = dp[i - 1][j - 1] + 1;
			//相等的话就让最大公共子序列长度+1
			else
			{
				dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
				//两种情况都试一下,取最大值
			}
		ans = max(ans, dp[i][j]);
		}
	}
	cout << ans;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值