状态转移图
分析
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;
}