题目
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
char X[1001],Y[1001],LCS[1001]; //X,Y数组用于存放输入数据,LCS数组用于存放
int L[1001][1001];
int F[1001][1001];
int i,j;
int main()
{
cin>>X;
cin>>Y;
int xlen=strlen(X); //xlen存放X数组的长度
int ylen=strlen(Y); //ylen存放Y数组的长度
for(i=1;i<=xlen;i++)
{
for(j=1;j<=ylen;j++)
{
if(X[i-1]==Y[j-1]) //如果当前X的值等于当前Y的值
{
L[i][j]=L[i-1][j-1]+1; //当前LCS的长度加一
F[i][j]=0; //当前标志位为0代表方向↘(向右下)
}
else if(L[i][j-1]>=L[i-1][j]) //如果左边第一个的LCS长度大于等于上边第一个的LCS长度
{
L[i][j]=L[i][j-1]; //当前LCS长度等于左边第一个的LCS长度
F[i][j]=1; //当前标志位为1代表→(向右)
}
else //如果上边第一个的LCS长度大于左边第一个的LCS长度
{
L[i][j]=L[i-1][j]; //当前LCS长度等于 上边第一个的LCS长度
F[i][j]=-1; //当前标志位为-1代表↓(向下)
}
}
}
i=xlen; //i等于X数组的长度
j=ylen; //j等于Y数组的长度
int k=L[i][j]; //k等于LCS表最右下方的长度
for(;i>0&&j>0;) //当i和j都大于0时
{
if(F[i][j]==0) //如果当前标志位为0,代表当前X,Y数组的输入数据相同,且标志位为↘
{
LCS[--k]=X[i-1]; //LCS输出数组的k-1位为当前X,Y数组的字符
i--; //X数组位置向上移动一位
j--; //Y数组位置向左移动一位
}
else if(F[i][j]==1) //如果当前标志位为1,代表标志位为→
{
j--; //Y数组位置向左移动一位
}
else //其他情况则为,当前标志位为-1,代表标志位为↓
{
i--; //X数组位置向上移动一位
}
}
cout<<LCS; //直接输出LCS 最长公共子序列
return 0;
}
总结
LCS问题归根结底是一个动态规划的问题,只要明白如何求解LCS问题,搞懂LCS的动态转移方程,就能解得此题.
动态转移方程
如果Am==Bn, LCS(Am,Bn) = LCS(Am-1,Bn-1) + 1
如果 Am !=Bn,LCS(Am,Bn) = max { LCS(Am-1,Bn),LCS(Am,Bn-1) }
即填表规则为:如果两个字符相同,该数值取其对角线 + 1,如果不同,取它左边或者上面相邻数值的最大值。
动态规划(打表)