卧薪尝胆,厚积薄发。
HNOI2004 打鼹鼠
Date: Sat Sep 15 11:16:24 CST 2018 In Category: NoCategory

Description:

一个 $n\times n$ 的网格图,有 $m$ 个鼹鼠会依次冒出来,给出每个鼹鼠冒出来的时间 $t$ (按顺序给出),位置 $(x,y)$ ,有一个机器人,最开始的位置任意,问最多能打几个鼹鼠。
$1\le m\le 10000$

Solution:

设 $f[i]$ 表示最后一个打 $i$ 最多能打几个,转移为 $\begin{align}f[i]=\max_{j=1}^{i-1}(f[j]+1)(|x[i]-x[j]|+|y[i]-y[j]|\le t[i]-t[j])\end{align}$ ,然而这样 $O(M^2)$ 不能通过,考虑 $DP$ 剪枝,记一个 $\begin{align}mx[i]=\max_{j=1}^{i}f[j]\end{align}$ ,那么 $mx[i]$ 单调递增在枚举 $j$ 时倒序循环,遇到 $mx[j]+1\le f[i]$ 就 $break$ 。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
inline int read()
{
register int res = 0;
register char c = getchar();
while(!isdigit(c))c = getchar();
while(isdigit(c))
{
res = (res << 1) + (res << 3) + c - '0';
c = getchar();
}
return res;
}
int n,m;
#define MAXM 10010
struct mole
{
int x,y,t;
}s[MAXM];
int f[MAXM];
int mx[MAXM];
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= m;++i)
{
scanf("%d%d%d",&s[i].t,&s[i].x,&s[i].y);
f[i] = 1;
for(int j = i - 1;j >= 1;--j)
{
if(mx[j] + 1 <= f[i])break;
if(abs(s[i].x - s[j].x) + abs(s[i].y - s[j].y) <= s[i].t - s[j].t)
{
f[i] = max(f[i],f[j] + 1);
}
}
mx[i] = max(mx[i - 1],f[i]);
}
int ans = 0;
for(int i = 1;i <= m;++i)
{
ans = max(ans,f[i]);
}
cout << ans << endl;
return 0;
}
In tag: DP-DP
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡