题目
给定两个长度分别为 N 和 M 的字符串 A 和 B,求既是 A 的子序列又是 B 的子序列的字符串长度最长是多少。
输入格式
第一行包含两个整数 N 和 M。
第二行包含一个长度为 N 的字符串,表示字符串 A。
第三行包含一个长度为 M 的字符串,表示字符串 B。
字符串均由小写字母构成。
输出格式
输出一个整数,表示最大长度。
数据范围
1≤N,M≤1000
输入样例:
4 5
acbd
abedc
输出样例:
3
思路
状态表示:
集合:dp[i][j]表示 所有 a[1~i] 和 b[1~j] 的所有公共子序列的最大值 子序列的意思是序列中某个元素可包含和可不包含
dp[i][j]集合 a[0]a[1]…a[i] b[0]b[1]b…b[j] a[i]和b[j]可含或不含,集合分为4类:
当子序列包含a[i]和b[j]时,并且当a[i] == b[j]时,dp[i][j] == dp[i-1][j-1] + 1
当子序列不包含a[i]和b[j]时,dp[i][j] == dp[i-1][j-1]
当子序列包含a[i]但不包含b[j]时,dp[i][j-1] 表示 所有 a[1~i] 和 b[1~j-1] 的所有公共子序列,涵盖了包含和不包含b[j]的情况,由取最大值的性质可知结果不变
当子序列不包含a[i]但包含b[j]时,dp[i-1][j] 表示 所有 a[1~i-1] 和 b[1~j] 的所有公共子序列,涵盖了包含和不包含a[i]的情况
状态计算:
dp[i][j] = max(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]);
if(a[i] == b[j])
dp[i][j] = max(dp[i][j], dp[i-1][j-1] + 1);
代码
#include <iostream>
using namespace std;
const int N = 1010;
int dp[N][N];
char a[N], b[N];
// 状态表示:
// 集合:dp[i][j]表示 所有 a[1~i] 和 b[1~j] 的所有公共子序列的最大值 子序列的意思是序列中某个元素可包含和可不包含
// dp[i][j]集合 a[0]a[1]...a[i] b[0]b[1]b...b[j] a[i]和b[j]可含或不含,集合分为4类:
// 当子序列包含a[i]和b[j]时,并且当a[i] == b[j]时,dp[i][j] == dp[i-1][j-1] + 1
// 当子序列不包含a[i]和b[j]时,dp[i][j] == dp[i-1][j-1]
// 当子序列包含a[i]但不包含b[j]时,dp[i][j-1] 表示 所有 a[1~i] 和 b[1~j-1] 的所有公共子序列,涵盖了包含和不包含b[j]的情况,由取最大值的性质可知结果不变
// 当子序列不包含a[i]但包含b[j]时,dp[i-1][j] 表示 所有 a[1~i-1] 和 b[1~j] 的所有公共子序列,涵盖了包含和不包含a[i]的情况
// 状态计算:if(a[i] == b[j]) dp[i][j] = dp[i][j-1]+1; else dp[i][j] = dp[i][j-1];
int main()
{
int n, m;
cin >> n >> m;
cin >> a+1 >> b+1;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++){
dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
if(a[i] == b[j]) dp[i][j] = max(dp[i][j], dp[i-1][j-1] + 1);
}
cout << dp[n][m] << endl;
return 0;
}