问题描述
最长公共子序列问题(Longest Common Subsequence problem, LCS)是求两个给定序列X={x1, x2, …, xm}与Y={y1, y2, …, yn}最长公共子序列的问题。
如果序列Z同时为X和Y的子序列,那么Z就称为X与Y的公共子序列。例,设X={a, b, c, b, d, a, b};Y={b, d, c, a, b, a},那么序列{b, c, a}就是X与Y的公共子序列。但是其并不是最长公共子序列,还存在{b, c, b, a},它才是两者的最长公共子序列(之一)。
输入: 给定多组数据。第1行输入数组组数q。接下来的2 * q行输入数据组,每组数据包含X、Y共2个字符串,每个字符串占1行。
输出: 输出每组X、Y的最长公共子序列Z的长度,每个长度占1行。
限制:
1 ≤ q ≤ 150
1 ≤ X、Y的长度 ≤ 1000
若某组数据中X或Y的长度超过100,则q不超过20。
输入示例
3
abcbdab
bdcaba
abc
abc
abc
bc
输出示例
4
3
2
讲解
我们用Xi代表{x1, x2, …, xi},用Yj代表{y1, y2, …, yj}。那么,求长度分别为m、n的两个序列X、Y的LCS,就相当于求Xm与Yn的LCS。我们将其分割为局部问题进行分析。
要考虑以下两种情况。
- xmx_mxm = yny_nyn时,在Xm−1X_{m-1}Xm−1与Yn−1Y_{n-1}Yn−1的LCS后面加上xm(=yn)x_m(=y_n)xm(=yn)就是XmX_mXm与YnY_nYn的LCS。
- xm≠ynx_m\neq y_nxm̸=yn时,Xm−1X_{m-1}Xm−1与YnY_nYn的LCS和Yn−1Y_{n-1}Yn−1的LCS中更长的一方就是XmX_mXm与YnY_nYn的LCS
这个算法对XiX_iXi与YjY_jYj同样适用。于是准备下述函数解决LCS局部问题。
c[m+1][n+1]该二维数组中,c[i][j]代表XiX_iXi与 YjY_jYj 的LCS长度。
c[i][j]的值可由下述递推公式(Recursive Formula)求得
c[i][j]={0ifi=0orj=0c[i−1][j−1]+1ifi,j>0andxi=yimax(c[i][j−1],c[i−1][j]ifi,j>0andxi≠yic[i][j]= \begin{cases} 0 & if & i=0&or&j=0\\ c[i-1][j-1]+1&if&i,j>0&and&x_i=y_i\\ max(c[i][j-1],c[i-1][j]&if&i,j>0&and&x_i\neq y_i \end{cases}c[i][j]=⎩⎪⎨⎪⎧0c[i−1][j−1]+1max(c[i][j−1],c[i−1][j]ifififi=0i,j>0i,j>0orandandj=0xi=yixi̸=yi
基于上述变量和公式,可以用动态规划法求序列X与Y的LCS,具体算法如下。
lcs(X, Y)
m = X.length
n = Y.length
for i = 1 to m
c[i][0] = 0
for j = 1 to n
c[0][j] = 0
for i = 1 to m
for j = 1 to n
if X[i] == Y[j]
c[i][j] = c[i-1][j-1] = c[i-1][j-1] + 1
else if c[i-1][j] >= c[i][j-1]
c[i][j] = c[i-1][j]
else
c[i][j] = c[i][j-1]
AC代码如下
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
static const int N = 1000;
int lcs(string X, string Y){
int c[N + 1][N + 1];
int m = X.size();
int n = Y.size();
int maxl = 0;
X = ' ' + X;//在X[0]中插入空格
Y = ' ' + Y;//在Y[0]中插入空格
for(int i = 1; i <= m; i++) c[i][0] = 0;
for(int j = 1; j <= n; j++) c[0][j] = 0;
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){
if(X[i] == Y[j]){
c[i][j] = c[i - 1][j - 1] + 1;
} else {
c[i][j] = max(c[i - 1][j], c[i][j - 1]);
}
maxl = max(maxl, c[i][j]);
}
}
return maxl;
}
int main(){
string s1, s2;
int n; cin>>n;
for(int i = 0; i < n; i++){
cin>>s1>>s2;
cout<<lcs(s1, s2)<<endl;
}
return 0;
}