题目

给定两个长度分别为 N 和 M的字符串 A 和 B,求既是 A 的子序列又是 B 的子序列的字符串长度最长是多少。

输入格式

第一行包含两个整数 N 和 M。
第二行包含一个长度为 N的字符串,表示字符串 A。
第三行包含一个长度为 M的字符串,表示字符串 B。
字符串均由小写字母构成。

数据范围

1≤N,M≤1000

输出样例

4 5
acbd
abedc

输出结果

3

本题采用线性动态规划的方式进行思考,一共两个字符串定义f[N][N]二维数组用来标记字符串遍历的每一个位置
对于集合作四种划分:
情况1:a[i],b[j] 均存在于 最长公共子序列中 (前提a[i]==b[j])
情况2:a[i] 在,b[j] 不在 (无前提)
情况3:a[i],b[j] 均不在 (无前提)
情况4:a[i]不在,b[j]在 (无前提)
情况1:暂用f[i-1][j-1]+1表示
情况2:暂用f[i][j-1]表示
情况3:暂用f[i-1][j-1]表示
情况4:暂用f[i-1][j]表示

情况2包含了情况2和情况3,情况4包含了情况4和情况3,对三种情况做max虽然答案会有交集的部分但是不会影响max之后的结果(非常重要的思想)

综上可知,其实只有两种状况需要考虑(1)对情况2和情况4 取 max (2)当遍历的数字相同的时候 f[i][j] = f[i-1][j-1]+1

代码

#include <iostream>
using namespace std;

const int N  = 1010;

char a[N],b[N];
int f[N][N];
int n,m;

int main()
{
    cin >> n >>m;
    //下标从下表1开始读入
    cin >> a + 1 >> b + 1;
    for(int i = 1;i <= n;i++)
    {
        for(int j = 1;j <= m;j++)
        {
            f[i][j] = max(f[i-1][j],f[i][j-1]);
            if(a[i] == b[j]) f[i][j] = f[i-1][j-1] + 1;
        }
    }
    cout << f[n][m];
    return 0;
}