[BZOJ 1207] [HNOI 2004] 打鼹鼠 【DP】
题目链接:BZOJ - 1207
题目分析
每一次打鼹鼠一定是从上一次打某只鼹鼠转移过来的,从打第 j 只鼹鼠能不能转移到打第 i 只鼹鼠,算一下曼哈顿距离和时间差就知道了。
那么就有一个 DP ,用 f[i] 表示打完第 i 只鼹鼠时最多打了多少只鼹鼠,然后 f[i] 可以由 f[1] .. f[i-1] 转移,类似于最长上升子序列。
然而这道题不能像最长上升子序列一样二分优化或树状数组优化,只能加一个判断 Maxf[] 都不够大就退出的优化。见代码。
代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int MaxN = 10000 + 5; int n, Ans; int f[MaxN], Maxf[MaxN], x[MaxN], y[MaxN], t[MaxN]; inline int Abs(int x) {return x < 0 ? -x : x;} int main() { int Fun; scanf("%d%d", &Fun, &n); Ans = 0; for (int i = 1; i <= n; ++i) { scanf("%d%d%d", &t[i], &x[i], &y[i]); f[i] = 1; for (int j = i - 1; j >= 1; --j) { if (Maxf[j] + 1 <= f[i]) break; if (f[j] + 1 > f[i] && (Abs(x[i] - x[j]) + Abs(y[i] - y[j]) <= t[i] - t[j])) f[i] = f[j] + 1; } Maxf[i] = Maxf[i - 1]; if (f[i] > Maxf[i]) Maxf[i] = f[i]; if (f[i] > Ans) Ans = f[i]; } printf("%d\n", Ans); return 0; }