输入
第1行:字符串A 第2行:字符串B (A,B的长度 <= 1000)
输出
输出最长的子序列,如果有多个,随意输出1个。
输入示例
abcicba abdkscab
输出示例
abca
请选取你熟悉的语言,并在下面的代码框中完成你的程序,注意数据范围,最终结果会造成Int32溢出,这样会输出错误的答案。
不同语言如何处理输入输出,请查看下面的语言说明。
题目链接:
https://www.51nod.com/tutorial/course.html#!courseId=4
题意:
给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的)。
比如两个串为:
abcicba
abdkscab
ab是两个串的子序列,abc也是,abca也是,其中abca是这两个字符串最长的子序列。
解题思路:
我们有两个字符串a[i]和b[i],设一个二维数组dp[i][j]表示a的i位和b的j位之前的最长公共子序列的长度。
1.a[i]=b[j]时,那么最长公共子序列的最后一个元素一定是这个元素。就有:dp[i][j]=dp[i-1][j-1]+1;
2.a[i]≠b[i]时,如果最长公共子序列中最后一个元素不等于a[i],那么最长公共子序列跟a[i]就没有关系,就有dp[i][j]=dp[i-1][j]
如果最长公共子序列中最后一个元素不等于b[i],那么最长公共子序列跟b[i]就没有关系,就有dp[i][j]=dp[i][j-1]
可是你事先并不知道最长公共子序列中最后一个元素和a[i],b[i]与没有关系,所以就有dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
回溯法标记路径:
由上面我们可以知道dp[i][j]的来源有三个
那么我们在计算dp[i][j]时,可以用x[i][j]来做标记,用来记录dp[i][j]是从哪个方向来的。用递归回溯的方法就可以打印路径。
AC代码:
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
int dp[1001][1001],x[1001][1001];
char a[1001],b[1001];
void print_load(int i,int j)
{
if(i==0||j==0)
return;
if(x[i][j]==0)
{
print_load(i-1,j-1);
printf("%c",a[i-1]);
}
else if(x[i][j]==1)
print_load(i,j-1);
else
print_load(i-1,j);
}
int main()
{
while(~scanf("%s%s",a,b))
{
memset(dp,0,sizeof(dp));
int a1=strlen(a);
int b1=strlen(b);
for(int i=1;i<=a1;i++)
{
for(int j=1;j<=b1;j++)
{
if(a[i-1]==b[j-1])
{
dp[i][j]=dp[i-1][j-1]+1;
x[i][j]=0;
}
else if(dp[i][j-1]>dp[i-1][j])
{
dp[i][j]=dp[i][j-1];
x[i][j]=1;
}
else
{
dp[i][j]=dp[i-1][j];
x[i][j]=-1;
}
}
}
print_load(a1,b1);
printf("\n");
}
return 0;
}