1.题目链接。求最长公共上升子序列。
2.设F[i,j]表示A[1..i]与B[1..j]并且以B[j]结尾的两段最长公共上升子序列,那么我们可以发现这样的转移
(1)A[i]==B[j]时
F[i][j]=max(F[i-1][k])+1,其中k满足1<=k<=j并且B[j]<A[i].
(2)如果不相等:
F[i][j]=F[i-1][j]
这样我们三重循环就可以搞定。但是这里是可以优化的。
我们考虑这样的一个事实:我们知道这样的一个事实,再第二层循环的时候,我们其实在枚举j。我们把满足条件的k叫做决策集合:S(i,j)。在j增加的时候,我们需要判断j是否可以被加入这个集合。所以我们需要检查:B[j]和A[i]的大小关系。如果满足b[j]<a[i],那么我们就可以把他加入新的集合,这个时候我们只需要记录上一次的最最大值,没必要在循环找一遍。这样就可以优化一层循环。(参考了算法竞赛进阶指南这本书)
#include<bits/stdc++.h>
#include <algorithm>
using namespace std;
const int maxn = 3005;
int n, a[maxn], b[maxn], f[maxn][maxn];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for (int i = 1; i <= n; ++i) scanf("%d", &b[i]);
for (int i = 1; i <= n; ++i)
{
int temp = 0;
for (int j = 1; j <= n; ++j) {
if (a[i] == b[j]) f[i][j] = temp + 1;
else f[i][j] = f[i - 1][j];
if (b[j] < a[i]) temp = max(temp, f[i][j]);
}
}
int ans = 0;
for (int i = 1; i <= n; ++i) ans = max(ans, f[n][i]);
printf("%d\n", ans);
return 0;
}