题目来源:https://www.51nod.com/tutorial/course.html#!courseId=4
给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的)。
比如两个串为:
abcicba
abdkscab
ab是两个串的子序列,abc也是,abca也是,其中abca是这两个字符串最长的子序列。
输入
第1行:字符串A 第2行:字符串B (A,B的长度 <= 1000)
输出
输出最长的子序列,如果有多个,随意输出1个。
输入示例
abcicba abdkscab
输出示例
abca
分析:
第一次做lcs题目,看似不难,但其实是有很多细节需要去灵活掌握的。
先看一张图:(来源51nod)
用动态规划的话,就相当于遍历两个字符串正交形成的矩阵。
有点像走迷宫的题了。然而此题需要记录路径,正好可以用走迷宫的思想记录路径。
用一个pre二维数组记录每个坐标的前驱方向,最后用回溯输出路径。
注意上图的规律,只有箭头往左上指的才是有字符相等关系的,
按图中灰色路径回溯到起点,再输出路径即可
代码:
#include<cstdio>
#include<cstring>
char s1[1100],s2[1100];
char ss[1001];
int dp[1100][1100];
int pre[1100][1100];
void output(int x,int y)
{
if(pre[x][y]==1)
{
output(x-1,y-1);
printf("%c",s1[x]);
}
if(pre[x][y]==2)
output(x-1,y);
if(pre[x][y]==3)
output(x,y-1);
}
int main()
{
while(~scanf("%s%s",s1,s2))
{
memset(pre,0,sizeof(pre));
memset(dp,0,sizeof(dp));
for(int i=0;s1[i];i++)
{
for(int j=0;s2[j];j++)
{
if(s1[i]==s2[j])
{
if(i==0||j==0)
dp[i][j]=1;
else
dp[i][j]=dp[i-1][j-1]+1;
pre[i][j]=1;//来自左上
}
else
{
if(dp[i-1][j]>dp[i][j-1])
{
dp[i][j]=dp[i-1][j];
pre[i][j]=2;//来自i-1
}
else
{
dp[i][j]=dp[i][j-1];
pre[i][j]=3;//来自j-1
}
}
}
}
int x=strlen(s1)-1;
int y=strlen(s2)-1;
output(x,y);
printf("\n");
}
return 0;
}