首先考虑最长公共子序列,需要两维数组,最长上升子序列,需要一维数组
由于最长公共子序列满足两个子序列相同,因此我们可以将二维数组的一维拿出来当作最长上升子序列的一维使用
故定义 \(f[i][j]\):以 \(b[j]\) 结尾的最长公共上升子序列
状态转移:由于b[j]必须有,因此我们可以枚举a[i]选不选
1. 选a[i]: f[i][j]=f[i-1][j]
2. 不选a[i]: if(a[i]==b[j]) f[i][j]=f[i-1][k]
枚举可能的k
for(i=1 to j-1)
if(b[i]<b[j])
f[i][j]=f[i-1][k]
\(O(N^3)\) 做法
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 3010;
int n, a[N], b[N];
int f[N][N];// f[i][j]以b[j]结尾的最长公共上升子序列的长度
int main()
{
cin >> n;
for(int i = 1; i <= n; i ++ ) cin >> a[i];
for(int i = 1; i <= n; i ++ ) cin >> b[i];
int res = 0;
for(int i = 1; i <= n; i ++ )
{
for(int j = 1; j <= n; j ++ )
{
// 不选 a[i]
f[i][j] = f[i - 1][j];
// 选 a[i]
if(a[i] == b[j])
{
// 前一个 b[k]
for(int k = 0; k < j; k ++ )
if(b[k] < b[j])
f[i][j] = max(f[i][j], f[i - 1][k] + 1);
}
res = max(res, f[i][j]);
}
}
// 注意最优解不一定以b[n]结尾
cout << res << endl;
return 0;
}
\(O(N^2)\) 做法
优化第三维枚举 \(k\) 的过程,我们发现,第三维循环每次都要求得满足 b[k]<b[j]
的 f[i-1][k] + 1
的最大值,因此我们可以把这个最大值提出来。
又因为,当需要枚举 \(k\) 时,一定有 b[j]==a[i]
,那么可以转化为维护 b[k]<a[i]
的 f[i-1][k] + 1
最大值,由于 \(i\) 处于第一层不变,那么就很好维护了。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 3010;
int n, a[N], b[N];
int f[N][N];// f[i][j]以b[j]结尾的最长公共上升子序列的长度
int main()
{
cin >> n;
for(int i = 1; i <= n; i ++ ) cin >> a[i];
for(int i = 1; i <= n; i ++ ) cin >> b[i];
int res = 0;
for(int i = 1; i <= n; i ++ )
{
int maxn = 1;
for(int j = 1; j <= n; j ++ )
{
f[i][j] = f[i - 1][j];
if(a[i] == b[j]) f[i][j] = max(maxn, f[i][j]);
if(a[i] > b[j]) maxn = max(maxn, f[i - 1][j] + 1);
res = max(res, f[i][j]);
}
}
// 注意最优解不一定以b[n]结尾
cout << res << endl;
return 0;
}
标签:int,res,公共,序列,include,最长
From: https://www.cnblogs.com/ALaterStart/p/18084909