最长公共子序列
最长公共子序列
题目描述
给定长度为 \(n\) 的数组 \(a\),长度为 \(m\) 的数组 \(b\),求其最长公共子序列长度
DP
\(f[i][j]\) 表示 \(a\) 前 \(i\) 项和 \(b\) 前 \(j\) 项的最长公共子序列长度
因为如果我们要在序列尾巴上加元素是不跟前面选了什么有关系的,所以没有后效性,珂以 DP
很显然我们可以选择不选 \(a_i\),所以可以转移 \(f[i-1][j]\)
我们亦可以不选 \(b_j\),所以可以转移 \(f[i][j-1]\)
如果要选 \(a_i\) 和 \(b_j\) 的话,必须满足 \(a_i=b_j\),因为是公共子序列,我们将 \(a_i\) 和 \(b_j\) 加进去,所以可以转移 \(f[i-1][j-1]+1\)
对于既不选 \(a_i\) 也不选 \(b_j\) 的状态,可以不用转移,因为肯定不会优于第三种,也已经在第一第二种中转移过了
综上,有
\[f[i][j]=max\{f[i-1][j],f[i][j-1],f[i-1,j-1]+1\}
\]
其中第三个状态要满足 \(a_i=b_j\) 才能转移,\(1\leq i\leq lena,1\leq j\leq lenb\)
初始化 \(f[i][0]=0,f[0][j]=0\),目标是 \(f[lena][lenb]\)
code
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);
}