题目大意
给定两个序列,求他们的最长公共上升子序列
样例
输入样例:
4
2 2 1 3
2 1 2 3
输出样例:
2
思路
状态表示
F[i, j] 表示 A1 - Ai 与 B1 - Bj 可以构成的以 Bj 为结尾的LCIS的长度
- 当Ai != Bj 时, F[i, j] = F [i - 1, j]
- 当Ai = Bj 时, F[i, j] = 前面最长上升公共子序列 + 1
这样用代码表示出来就是
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(a[i] == b[j])
for(int k = 0; k < j; k++){
if(b[k] < a[i])
f[i][j] = max(f[i][j], f[i - 1][k] + 1);
}
else f[i][j] = f[i - 1][j];
但是数据范围是3000, O(n ^ 3)时间复杂度显然不行
由于第三重循环是找出前面符合要求的最大的值, 所以我们在第二重循环时把它记录下来就行,相当于把代码做了等价转换,时间复杂度降低了一个量级。
最终代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N = 3010;
int a[N], b[N], f[N][N];
int 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 ++ ){
int val = 0;
//if(b[0] < a[i]) val = f[i - 1][0]
for (int j = 1; j <= n; j ++ ){
if(a[i] == b[j]) f[i][j] = val + 1;
else f[i][j] = f[i - 1][j];
if(b[j] < a[i]) val = max(val, f[i - 1][j]);
}
}
int ans = 0;
for(int i = 1; i <= n; i++) ans = max(ans , f[n][i]);
cout << ans << endl;
return 0;
}