原题链接:
题解:
第一种理解:
还是按照闫氏DP法来做,状态表示则需要经验积累。
首先定义集合,该集合包含所有A[1~i]与B[1~j]的公共子序列。
接着定义属性,由于我们要获得最长公共子序列,属性便为Max。
f[i][j]表示所有A[1~i]与B[1~j]的公共子序列中的最长公共子序列的长度。
然后就是分析状态计算,根据不重不漏的指导思想,我们将f[i][j]分为4种情况,分别是①既不包含a[i]也不包含b[j];②不包含a[i]但包含b[j];③包含a[i]但不包含b[j];④既包含a[i]也包含b[j]。注意这里的包含指的是一定包含的意思。
对于①而言:其实质就是f[i-1][j-1];
对于②而言:其实质就是f[i-1][j]么?并不完全是,我们之前提到过,这里的包含代表的是一定不包含a[i]但包含b[j]。但是f[i-1][j]的含义是所有A[1~i-1]与B[1~j]的公共子序列中的最长公共子序列的长度,也即一定不包含a[i]但可以包含b[j]也可以不包含b[j-1]。也即f[i-1][j]代表的是②和①的情况。
对于③而言:其实质就是f[i][j-1]么?并不完全是,我们之前提到过,这里的包含代表的是一定包含a[i]但不包含b[j]。但是f[i][j-1]的含义是所有A[1~i]与B[1~j-1]的公共子序列中的最长公共子序列的长度,也即可以包含a[i]也可以不包含a[i]但一定不包含b[j]。也即f[i][j-1]代表的是①和③的情况。
对于④而言:两者相同时一定包含的话就等于f[i-1][j-1]+1。
综上,由于f[i-1][j]代表的是②和①的情况,f[i][j-1]代表的是①和③的情况。所以我们首先可以取这两者之间的最大值,然后再判断情况④即可。
第二种理解:
这题的状态分成两半考虑比较方便,按两个序列末尾的字符是不是相等来区分。
如果两个字符相等,就可以直接转移到f[i-1][j-1],不相等的话,两个字符一定有一个可以抛弃,可以对f[i-1][j],f[i][j-1]两种状态取max来转移。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
int n, m, f[N][N];
char a[N], b[N];
int main() {
cin >> n >> m >> a + 1 >> b + 1;
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= m;j++) {
if (a[i] == b[j]) f[i][j] = f[i - 1][j - 1] + 1;
else f[i][j] = max(f[i - 1][j], f[i][j - 1]);
}
}
cout << f[n][m];
}