51Nod 1006 最长公共子序列Lcs(动态规划)

最长公共子序列Lcs

给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的)。

比如两个串为:

abcicba

abdkscab

ab是两个串的子序列,abc也是,abca也是,其中abca是这两个字符串最长的子序列。

Input

第1行:字符串A
第2行:字符串B
(A,B的长度 <= 1000)

Output

输出最长的子序列,如果有多个,随意输出1个。

Sample Input

abcicba
abdkscab

Time limit

1000 ms

Memory limit

131072 kB

Author

李陶冶

Sample Output

abca

题解:经典的DP问题。

状态dp[i][j]:a串的前i项和b串的前j项以b[j]项为结尾构成的LCIS的长度.

状态转移方程:dp[i][j]=max(dp[i-1][j],dp[i][j-1],dp[i-1][j-1]+(a[i]==b[j]?1:0))。

ps:如果a串的i项和b串的j项相等,dp[i][j]就等于dp[i][j]+1,否则就等于前一个其他情况中的最大值。

这一题的难点在于如何回溯找到路线。博主也蒙呀,看了好多博客,找到了一个很好理解很简介的思路方法:当dp[i][j]最大的时候,就是a[i][j]==b[i][j]的时候。不断找到dp[i][j]的最大值,直到i或者j等于0,也就回溯了找到最长公共子序列的路线。

具体代码如下:

#include<iostream>
using namespace std;
int dp[1002][1002]={0};
int MAX(int a,int b,int c)
{
	if(c>b)
		b=c;
	return a>b?a:b;
}
int main()
{
	char final[1002]={0};
	char a[1002],b[1002];
	scanf("%s%s",a+1,b+1);
	int i,j;
	for(i=1;a[i];i++)
		for(j=1;b[j];j++)
			dp[i][j]=MAX(dp[i-1][j],dp[i][j-1],dp[i-1][j-1]+(a[i]==b[j]?1:0));
	i--;
	j--;
	int k=1001;
	while(i>0&&j>0)
		if(a[i]==b[j])
		{
			final[k--]=a[i];
			i--;
			j--;			
		}else if(dp[i-1][j]>dp[i][j-1])
			i--;
		else j--;
	printf("%s\n",final+k+1);
	return 0;
}

ps:有什么问题或者错误,大佬们在评论留言呀,我会改的,谢谢!

猜你喜欢

转载自blog.csdn.net/qq_42391248/article/details/81264797
今日推荐