[AcWing 897] 最长公共子序列

image

复杂度 \(O(n \cdot m)\)

总体复杂度 $ 1000 \times 1000 = 1 \times 10^{6} $


点击查看代码
#include<iostream>

using namespace std;
const int N = 1010;

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

int main()
{
	cin >> n >> m >> 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] = max(f[i][j], f[i - 1][j - 1] + 1);
		}
	cout << f[n][m] << endl;
	return 0;
}

  1. 状态表示
    $ f[i][j] $ 表示所有在第一个序列的前 \(i\) 个字母中出现,并且在第二个序列的前 \(j\) 个字母中出现的子序列
  2. 状态转移
    $ f[i][j] $ 可以分成四种情况:
    ① 不选 \(a[i]\)\(b[j]\) ,等价于 \(f[i - 1][j - 1]\)
    ② 选 \(a[i]\)\(b[j]\) ,如果 \(a[i] = b[j]\) ,等价于 \(f[i - 1][j - 1] + 1\)
    ③ 选 \(a[i]\) ,不选 \(b[j]\) ,包含于 \(f[i][j - 1]\)
    ③ 不选 \(a[i]\) ,选 \(b[j]\) ,包含于 \(f[i - 1][j]\)
    取四种情况的最大值,而 $ f[i - 1][j - 1] $ 包含于 $ f[i][j - 1] $ 和 \(f[i - 1][j]\) ,故只需取三种情况的最大值
    \(f[i][j] = max(f[i][j - 1], f[i - 1][j], f[i - 1][j - 1] + 1)\)
  3. 也可以这样分类:
    ① 选 \(a[i]\)\(b[j]\) ,如果 \(a[i] = b[j]\) ,等价于 \(f[i - 1][j - 1] + 1\)
    ② 不选 \(a[i]\) ,等价于 \(f[i - 1][j]\)
    ③ 不选 \(b[j]\) ,等价于 \(f[i][j - 1]\)
posted @ 2022-05-23 21:07  wKingYu  阅读(67)  评论(0)    收藏  举报