题目描述
一个给定序列的子序列是在该序列中删去若干元素(也可以不删去)后得到的序列。例如Z=“BCDB” 就是X="ABCBDAB"的一个子序列,而Z=“CBBD"则不是X的子序列。 给定三个序列 X,Y和Z,如果Z既是X的一个子序列又是Y的一个子串,则称Z是X和Y的公共子序列。
例如X="ABCBDAB”,Y=BDCABA",则序列"BCA"即为X和Y的一个公共子序列,但不是X和Y的最长公共子序列(LCS),因为还有比它更长的公共子序列"BCBA"。事实上"BCBA"是X和Y的一个LCS ,"BDAB"也是一个LCS。 现输入两个序列X和Y,要求出X和Y的最长公共子序列。
输入格式
第1行:两个用字符串表示的序列X和Y。1<=X.size(),Y.size()<=1000,两个序列之间用1个空格分隔。序列均由大写字母组成。
输出格式
第1行:一个整数L,表示两个序列的最长公共子序列的长度。
解题思路
这题显然要用到动态规划,
本题是动态规划的经典题目,我们便设f[i][j]为截至字符串X的第i个字符和字符串Y的第j个字符时,最长公共子序列的长度。
状态转移方程
那f[i]j[j]有两种情况:
(1)X[i]与Y[j]相同,则我们只需考虑f[i-1][j-1],再加1即可。即f[i][j]=f[i-1][j-1]+1
(2)X[i]与Y[j]不相同,则我们就看f[i-1][j]的值和f[i][j-1]的值,两者取最大值即可。即f[i][j]=max(f[i-1][j],f[i][j-1])
实现成代码:
if(x[i]==y[j]) f[i][j]=f[i-1][j-1]+1;
else f[i][j]=max(f[i-1][j],f[i][j-1]);
初始化
因为f[1][1]本身为0,定义在main函数外就自动初始化为0了,所以不用写 memset(f,0,sizeof(f)) 了。
循环次数
我们设len1为字符串X的长度,len2为字符串Y的长度,则i就从1循环到len1,j从1循环到len2
备注:本蒟蒻输入时是从1开始的,详细见下面的代码。
完整代码:
#include<bits/stdc++.h>
using namespace std;
char x[1005],y[1005];
int f[1005][1005],a[1005];
int main()
{
scanf("%s %s",x+1,y+1);
int len1=strlen(x+1),len2=strlen(y+1);
for(int i=1;i<=len1;i++)
{
for(int j=1;j<=len2;j++)
{
if(x[i]==y[j]) f[i][j]=f[i-1][j-1]+1;
else f[i][j]=max(f[i-1][j],f[i][j-1]);
}
}
printf("%d\n",f[len1][len2]);
return 0;
}
这是本蒟蒻的第一篇博客,写得不好请见谅🙏。并且希望能帮到和我一样菜的蒟蒻程序猿们。