BZOJ 1207 [HNOI2004]打鼹鼠:dp【类似最长上升子序列】

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1207

题意:

  有一个n*n的网格,接下来一段时间内会有m只鼹鼠出现。

  第i只鼹鼠会在tim[i]秒出现,位置为(x[i],y[i])。数据保证tim[i]递增给出。

  你有一个打鼹鼠的机器,初始位置可以自定。机器每秒钟只能原地不动或者走一格。在某一秒机器位置与鼹鼠出现的位置相同时,认为这个鼹鼠被打到。

  问你最多能打多少鼹鼠。

题解:

  乍一看和HDU 1176 免费馅饼很像:

    dp[i][x][y] = 第i秒在(x,y)最多打的鼹鼠数

  但是时间和空间都会爆。。。

  for循环时间:O(n^4 * m)

  改为记忆化搜索:O(n^2 * m^2)

  (时间 = 枚举起始位置 * 求dp)

  打鼹鼠有一个和最长上升子序列相似的性质:

    打鼹鼠:如果tim[i] < tim[j],那么鼹鼠j只可能在鼹鼠i出现之后打。

    LIS:如果i < j,那么s[j]只可能在考虑完s[i]之后加入答案。

  表示状态:

    dp[i] = max hit

    i:打了第i只鼹鼠

  找出答案:

    max dp[i]

  如何转移:

    dp[i] = max dp[j] + 1 (j < i, tim[i]-tim[j] >= manhattan(ci,cj))

    (j在i之前,并且可以在限定时间内从j到达i(曼哈顿距离)

  边界条件:

    set dp = 1

    至少打了自己。

AC Code:

 1 // state expression:
 2 // dp[i] = max hit
 3 // i: ith mole is dead
 4 //
 5 // find the answer:
 6 // max dp[i]
 7 //
 8 // transferring:
 9 // dp[i] = max dp[j] + 1 (tim[i]-tim[j] >= manhattan(ci,cj))
10 //
11 // boundary:
12 // set dp = 1
13 #include <iostream>
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #define MAX_M 10005
18 
19 using namespace std;
20 
21 int n,m;
22 int ans=0;
23 int x[MAX_M];
24 int y[MAX_M];
25 int tim[MAX_M];
26 int dp[MAX_M];
27 
28 void read()
29 {
30     cin>>n>>m;
31     for(int i=0;i<m;i++)
32     {
33         cin>>tim[i]>>x[i]>>y[i];
34     }
35 }
36 
37 void solve()
38 {
39     for(int i=0;i<m;i++)
40     {
41         dp[i]=1;
42         for(int j=0;j<i;j++)
43         {
44             if(tim[i]-tim[j]>=abs(x[i]-x[j])+abs(y[i]-y[j]))
45             {
46                 dp[i]=max(dp[i],dp[j]+1);
47             }
48         }
49         ans=max(ans,dp[i]);
50     }
51 }
52 
53 void print()
54 {
55     cout<<ans<<endl;
56 }
57 
58 int main()
59 {
60     read();
61     solve();
62     print();
63 }
原文地址:https://www.cnblogs.com/Leohh/p/7504974.html