跳过正文
  1. Posts/

BZOJ 1207: [HNOI2004]打鼹鼠 (LIS)

·2 分钟
目录

1207: [HNOI2004]打鼹鼠
#

Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 2854  Solved: 1390 [Submit][Status][Discuss]

Description
#

鼹鼠是一种很喜欢挖洞的动物,但每过一定的时间,它还是喜欢把头探出到地面上来透透气的。根据这个特点阿Q编写了一个打鼹鼠的游戏:在一个nn的网格中,在某些时刻鼹鼠会在某一个网格探出头来透透气。你可以控制一个机器人来打鼹鼠,如果i时刻鼹鼠在某个网格中出现,而机器人也处于同一网格的话,那么这个鼹鼠就会被机器人打死。而机器人每一时刻只能够移动一格或停留在原地不动。机器人的移动是指从当前所处的网格移向相邻的网格,即从坐标为(i,j)的网格移向(i-1, j),(i+1, j),(i,j-1),(i,j+1)四个网格,机器人不能走出整个nn的网格。游戏开始时,你可以自由选定机器人的初始位置。现在你知道在一段时间内,鼹鼠出现的时间和地点,希望你编写一个程序使机器人在这一段时间内打死尽可能多的鼹鼠。

Input
#

第一行为n(n<=1000), m(m<=10000),其中m表示在这一段时间内出现的鼹鼠的个数,接下来的m行每行有三个数据time,x,y表示有一只鼹鼠在游戏开始后time个时刻,在第x行第y个网格里出现了一只鼹鼠。Time按递增的顺序给出。注意同一时刻可能出现多只鼹鼠,但同一时刻同一地点只可能出现一只鼹鼠。

Output
#

仅包含一个正整数,表示被打死鼹鼠的最大数目

Sample Input
#

2 2 1 1 1 2 2 2

Sample Output
#

1

HINT
#

Source
#

思路:很巧妙的题目。类比LIS,如果两只仓鼠的曼哈顿距离小于等于两只仓鼠出现的时间,那么就可以从一只仓鼠转移到另一只仓鼠。利用这个条件,做二维的LIS即可。

 1/* ***********************************************
 2Author :111qqz
 3Created Time :2017年01月26日 星期四 15时39分26秒
 4File Name :1207.cpp
 5************************************************ */
 6
 7#include <cstdio>
 8#include <cstring>
 9#include <iostream>
10#include <algorithm>
11#include <vector>
12#include <queue>
13#include <set>
14#include <map>
15#include <string>
16#include <cmath>
17#include <cstdlib>
18#include <ctime>
19#define fst first
20#define sec second
21#define lson l,m,rt<<1
22#define rson m+1,r,rt<<1|1
23#define ms(a,x) memset(a,x,sizeof(a))
24typedef long long LL;
25#define pi pair < int ,int >
26#define MP make_pair
27
28using namespace std;
29const double eps = 1E-8;
30const int dx4[4]={1,0,0,-1};
31const int dy4[4]={0,-1,1,0};
32const int inf = 0x3f3f3f3f;
33const int N=1E4+7;
34int n,m;
35int t[N],x[N],y[N];
36int dp[N] ; //dp[i]表示第i只仓鼠出现的时候,最多能打死几只仓鼠。
37int main()
38{
39	#ifndef  ONLINE_JUDGE
40//	freopen("code/in.txt","r",stdin);
41  #endif
42
43	cin>>n>>m;
44	for ( int i = 1; i  <= m ; i++) scanf("%d%d%d",&t[i],&x[i],&y[i]);
45	int ans = 1;
46	ms(dp,0);
47	dp[1] = 1;
48	for ( int i = 2 ; i <= m ; i++)
49	{
50	    dp[i] = 1 ; //一个显然的结论是。。。初始位置一定在某个仓鼠处,而且如果在仓鼠i处,那么之前的仓鼠是放弃的。
51	    for ( int j = 1 ; j <= i-1 ; j++)
52	    {
53		if (abs(x[i]-x[j])+abs(y[i]-y[j])<=t[i]-t[j]) dp[i] = max(dp[i],dp[j]+1); //打完第j只仓鼠去打第i只仓鼠
54	    }
55	    ans = max(ans,dp[i]);
56	}
57	printf("%d",ans);
58  #ifndef ONLINE_JUDGE
59  fclose(stdin);
60  #endif
61    return 0;
62}

相关文章

最长上升子序列nlogn解法

·2 分钟
首先回顾一下n^2的做法。 状态转移方程为dp[i] =max(1,dp[j]) (1=<j<=i-1&&a[i]>a[j]) 1for ( int i = 1 ; i <= n ; i++) cin>>a[i]; 2 3 for ( int i = 1 ; i <= n ; i++) 4 { 5 dp[i] = 1; 6 for ( int j = 1 ; j < i ; j++) 7 { 8 if (a[i]>a[j]) 9 dp[i] = max(dp[i],dp[j]+1); 10 } 11 ans = max(ans,dp[i]); 12 } 然后我们发现,使得dp[i]得到同一个值的dp[j]可能有多个,那么选择哪个呢? 假设 x<y<i,a[x]<a[y],dp[x]==dp[y],那么我们选择x好还是y好呢? 显然是x好。为什么?因为选择x潜力大。因为可能在x,y之间存在一个z,满足a[x]<a[z]<a[y],如果选择a[y],就没有办法选择可能使长度更长的a[z]了。通俗得说。。我们要求的是最长上升子序列。。你一开始就弄那么大。。。后面还上哪上升去啊。。。长度小啊。。。

(dp专题004)hdu 2955Robberies(01背包变形)

·2 分钟
题目链接 题意: 给出n个银行 ,以及抢劫每个银行可以得到的价值和被抓的概率,不同银行之间被抓的概率是相互独立的,现在给出安全概率p,只有当概率从小于安全概率时才是安全的,问最多能抢劫多少价值。

(dp专题003)hdu 4055 Number String(dp)

·2 分钟
题目链接 题意:给出n(n<=1E3)个字符,字符可能为’D’,‘I’,’?’,第i位对应的字符分别表示,第i位大于第i+1位,第i位小于第i+1位,或者不确定。