↓ Skip to main content
  1. Posts/

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

·965 words·2 mins
Note: This article is available in Chinese only. 本文暂无英文版本。 View original

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}

Related

最长上升子序列nlogn解法

·856 words·2 mins
首先回顾一下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专题006)hdu 2602 Bone Collector(01背包)

·296 words·1 min
题目链接 题意:容量为V的背包,n个骨头,给出价值和体积,问最多能装多少价值的背包。 思路:01背包裸体。 代码实现 1/* *********************************************** 2Author :111qqz 3Created Time :2016年11月16日 星期三 15时14分36秒 4File Name :code/hdu/2602.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=1E3+7; 34int dp[N],value[N],cost[N]; 35int n,V; 36void solve(int v,int c) 37{ 38 for ( int i = V; i >= c; i --) 39 dp[i] = max(dp[i],dp[i-c]+v); 40} 41int main() 42{ 43 #ifndef ONLINE_JUDGE 44 freopen("code/in.txt","r",stdin); 45 #endif 46 int T; 47 cin>>T; 48 while (T--) 49 { 50 scanf("%d%d",&n,&V); 51 ms(dp,0); 52 for ( int i = 1 ;i <= n ; i++) scanf("%d",&value[i]); 53 for ( int i = 1; i <= n ; i++) scanf("%d",&cost[i]); 54 for ( int i = 1 ; i <= n ; i++) solve(value[i],cost[i]); 55 int ans = 0 ; 56 57 for ( int i = 0 ; i <= V ; i++) ans = max(ans,dp[i]); 58 printf("%d\n",ans); 59 } 60 61 #ifndef ONLINE_JUDGE 62 fclose(stdin); 63 #endif 64 return 0; 65}

[dp专题005]hdu 1864最大报销额(01背包,垃圾题)

·467 words·1 min
hdu1864题目链接 题意:中文题目,不多说了。 思路:正解是01背包,呵呵呵。 出题人是傻逼吗? 不给数据范围? 以及,正解的01背包基于所有的发票额度的只有2位小数。这是让人猜? 本来看到这题这么恶心时不打算写的…

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

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

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

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