熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目。
小沐沐先让奶牛研究了最长上升子序列,再让他们研究了最长公共子序列,现在又让他们研究最长公共上升子序列了。
小沐沐说,对于两个数列 A 和 B,如果它们都包含一段位置不一定连续的数,且数值是严格递增的,那么称这一段数是两个数列的公共上升子序列,而所有的公共上升子序列中最长的就是最长公共上升子序列了。
奶牛半懂不懂,小沐沐要你来告诉奶牛什么是最长公共上升子序列。
不过,只要告诉奶牛它的长度就可以了。
数列 A 和 B 的长度均不超过 3000。
输入格式
第一行包含一个整数 N,表示数列 A,B 的长度。
第二行包含 N 个整数,表示数列 A。
第三行包含 N 个整数,表示数列 B。
输出格式
输出一个整数,表示最长公共上升子序列的长度。
数据范围
1≤N≤3000,序列中的数字均不超过 231−1。
输入样例:
4
2 2 1 3
2 1 2 3
输出样例:
2
三重循环:超时,注意优化。
优化原因: s[i]是一个定值,每次寻找s1[k]<s[i]时都是重复计算。
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
int s[3001], s1[3001];
int dp[3001][3001];//表示从s[1]到s[i] 和是s1[i]到 s1[j]的相同的最长上升子序列
int main()
{
int n, m;
scanf("%d", &n);
for (int i = 1;i<=n;i++)
scanf("%d", &s[i]);
for (int i = 1;i<=n;i++)
scanf("%d", &s1[i]);
int res = 0;
for (int i = 1;i<=n;i++)
{
for (int j = 1;j<=n ;j++)
{
if(s[i]==s1[j])
{
for (int k = 0;k<j;k++)
{
if(s1[k]<s[i])
dp[i][j] = max(dp[i][j], dp[i - 1][k] + 1);
}
}
else
dp[i][j] = dp[i-1][j];
}
}
for (int i = 1;i<=n;i++)
res = max(res, dp[n][i]);
// for (int i = 1;i<=n;i++)
// {
// for (int j = 1;j<=n;j++)
// cout << dp[i][j] << " ";
// cout << endl;
// }
cout << res << endl;
return 0;
}
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
int s[3001], s1[3001];
int dp[3001][3001];//表示从s[1]到s[i] 和是s1[i]到 s1[j]的相同的最长上升子序列
int main()
{
int n, m;
freopen("11.txt", "r", stdin);
scanf("%d", &n);
for (int i = 1;i<=n;i++)
scanf("%d", &s[i]);
for (int i = 1;i<=n;i++)
scanf("%d", &s1[i]);
int res = 0;
for (int i = 1;i<=n;i++)
{
int Max = 0;//表示当s[i]==s1[j]的时候,此时s1[1......j-1]中最长的上升子序列的长度
for (int j = 1;j<=n ;j++)
{
dp[i][j] = dp[i-1][j];
if(s[i]==s1[j])
dp[i][j] = max(dp[i][j], Max+1);
if(s1[j]<s[i])
Max = max(Max, dp[i-1][j]);//判断以j结尾 跟新Max.
}
}
for (int i = 1;i<=n;i++)
res = max(res, dp[n][i]);
// for (int i = 1;i<=n;i++)
// {
// for (int j = 1;j<=n;j++)
// cout << dp[i][j] << " ";
// cout << endl;
// }
cout << res << endl;
return 0;
}