【动态规划常用解题思路】2 —— 最长公共子序列

        对于动态规划有一道很经典的题目(大家猜一猜),最长公共子序列,这道题虽然很经典,但是也是一道失分的难题,大家先看一看题目:

1821 - 最长公共子序列(LCS)(1)

题目描述

给出1-n的两个排列P1和P2,求它们的最长公共子序列。

输入

第一行是一个数n;(n是5~1000之间的整数)
接下来两行,每行为n个数,为自然数1-n的一个排列(1-n的排列每行的数据都是1-n之间的数,但顺序可能不同,比如1-5的排列可以是:1 2 3 4 5,也可以是2 5 4 3 1)。

输出

一个整数,即最长公共子序列的长度。

样例

输入

复制

5 
3 2 1 4 5
1 2 3 4 5
输出

复制

3

题目说的很清晰,就是在两个数组中找到最长相同数字的长度,如果还是不了解,我们就来解析一下,实例输入中有一个数组{3 2 1 4 5}一个数组{1 2 3 4 5},我们来找一找,发现最长公共子序列是{1 4 5},那么,题目看懂了,我们就可以开始解题了!!!!!

扫描二维码关注公众号,回复: 17338177 查看本文章

首先,跟上次我写的文章 —— 【动态规划常用解题思路】,一样,我们要先找dp数组表示的意思,从题目中得知,dp[i][j] = 表示以a[i]与b[j]为结尾的最长公共子序列;那么,了解了dp表示的意思后,便开始找递推的边界,可是找来找去也没有找出来,因为你无法保证a[1] 是否等于b[1],所以,这个程序就没有边界;接下来,我们可以开始找状态转移方程了,看看刚刚上面推的意思,dp[i][j]该如何从dp[i - 1][j] dp[i][j - 1].......推出来呢?很简单,dp[i][j]表是以a[i] 与 b[j] 为结尾的最长公共子序列可以从dp[i-1][j] 和 dp[i][j - 1]推出来,dp[i-1][j]表示以a[i - 1]与b[j]为结尾的最长公共子序列,举一反三,那么dp[i][j -1]就可以想一想,无非就是以a[i]与b[j - 1]为结尾的最长公共子序列,最后在max()一下,取一个最大值就行了,先别急着写,我们还没写完,因为我们判断的是不相等是的长度,所以我们继续推!!!if(a[i] == b[j])时,dp[i][j] = max(dp[i][j],dp[i-1][j-1] + 1);因为我们需要一个最值,所以需要max,而dp[i- 1][j-1]是什么呢,也就是以a[i-1]和b[i-1]为结尾的最长公共子序列,推好转移方程后就可以开始做最后的准备工作了,确定答案的位置,结合题目想一想,就知道了,因为它的答案就是由前面的数推出发来的,所以最后的答案就是在dp[n][n]项,好了,上代码!!!!

后续我会继续更新,下一篇(前缀和最大值)!

#include <bits/stdc++.h>
using namespace std;
const int N = 1e3+10;
int n;
int a[N],b[N],dp[N][N];
int main(){
	cin>>n;
	for(int i = 1;i<=n;i++) cin>>a[i];
	for(int i = 1;i<=n;i++) cin>>b[i];
	for(int i = 1;i<=n;i++){
		for(int j = 1;j<=n;j++){
			dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
			if(a[i] == b[j]){
				dp[i][j] = max(dp[i][j],dp[i-1][j-1]+1);
			}
		}
	} 
	cout<<dp[n][n];
	return 0;
}

猜你喜欢

转载自blog.csdn.net/nihaoxingshijie/article/details/134623782