POJ 3034 Whac-a-Mole(三維dp+處理小技巧)

畫船聽雨發表於2014-06-06

題目感覺不錯,以後還得再做做。

題意:打地鼠,n*n的棋盤,每秒特定的格子上會有地鼠出沒。給一個錘子,比如錘子前一次在(x1, y1),現在移動到

(x2, y2)。則它可以打掉(x1, y1) -> (x2, y2)連線上的所有地鼠。錘子每次最多移動的距離為d。求最後最多能打到

多少個地鼠。

主要的思路就是用該點求出與該點相鄰的點的狀態。

dp[t][x][y]表示時間為t是,錘子在(x, y)座標的最大值。列舉x,y,求t + 1時間到(xx, yy)的最優值, dis(x, y, xx,

 yy) <= d。在計算(x, y) -> (xx, yy)的時候不能一個單位一個單位的加,否則會超時。dx表示x -> xx的偏移量,

dy表示y -> yy的偏移量。

處理小技巧:求出dx, dy的最大公約數tp。 dx /= tp, dy /= tp。這樣從(x, y) 到(xx, yy)時沒次x += dx, y += dy;

Whac-a-Mole
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 3179   Accepted: 961

Description

While visiting a traveling fun fair you suddenly have an urge to break the high score in the Whac-a-Mole game. The goal of the Whac-a-Mole game is to… well… whack moles. With a hammer. To make the job easier you have first consulted the fortune teller and now you know the exact appearance patterns of the moles.

The moles appear out of holes occupying the n2 integer points (xy) satisfying 0 ≤ xy < n in a two-dimensional coordinate system. At each time step, some moles will appear and then disappear again before the next time step. After the moles appear but before they disappear, you are able to move your hammer in a straight line to any position (x2y2) that is at distance at most d from your current position (x1y1). For simplicity, we assume that you can only move your hammer to a point having integer coordinates. A mole is whacked if the center of the hole it appears out of is located on the line between (x1y1) and (x2y2) (including the two endpoints). Every mole whacked earns you a point. When the game starts, before the first time step, you are able to place your hammer anywhere you see fit.

Input

The input consists of several test cases. Each test case starts with a line containing three integers nd and m, where n and d are as described above, and m is the total number of moles that will appear (1 ≤ n ≤ 20, 1 ≤ d ≤ 5, and 1 ≤ m ≤ 1000). Then follow m lines, each containing three integers xy and t giving the position and time of the appearance of a mole (0 ≤ xy < n and 1 ≤ t ≤ 10). No two moles will appear at the same place at the same time.

The input is ended with a test case where n = d = m = 0. This case should not be processed.

Output

For each test case output a single line containing a single integer, the maximum possible score achievable.

Sample Input

4 2 6
0 0 1
3 1 3
0 1 2
0 2 2
1 0 2
2 0 2
5 4 3
0 0 1
1 2 1
2 4 1
0 0 0

Sample Output

4
2
#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define eps 1e-4
#define M 1000100
//#define LL __int64
#define LL long long
#define INF 0x7ffffff
#define PI 3.1415926535898

const int maxn = 63;

using namespace std;
int N;
int n, d, m;
struct node
{
    int x, y;
    double d;
} f[1010];
int dp[maxn][maxn][maxn];
int mp[maxn][maxn][maxn];

bool cmp(node a, node b)
{
    return a.d < b.d;
}
void init()
{
    N = 0;
    for(int i = -5; i <= 5; i++)
    {
        for(int j = -5; j <= 5; j++)
        {
            if(i*i + j*j <= 25)
            {
                f[N].x = i;
                f[N].y = j;
                f[N++].d = sqrt((i*i*1.0)+(j*j*1.0));
            }
        }
    }
    sort(f, f+N, cmp);
}

int Sum(int t, int x, int y, int xx, int yy, int dx, int dy)
{
    int cnt = 0;
    while(1)
    {
        cnt += mp[t][xx][yy];
        if(x == xx && y == yy)
            break;
        xx += dx;
        yy += dy;
    }
    return cnt;
}

bool judge(int x, int y)
{
    if(x < 0 || x >= n+2*d+1 || y < 0 || y >= n+2*d+1)
        return false;
    return true;
}

int main()
{
    init();
    while(cin >>n>>d>>m)
    {
        if(!n && !d && !m)
            break;
        int x1, y1, t;
        int max_t = 0;
        memset(dp, 0, sizeof(dp));
        memset(mp, 0, sizeof(mp));
        for(int i = 0; i < m; i++)
        {
            cin >>x1>>y1>>t;
            mp[t][x1+d][y1+d] = 1;
            max_t = max(max_t, t);
        }
        max_t++;
        for(int tt = 1; tt < max_t; tt++)
        {
            for(int x = 0; x < 2*d+n+1; x++)
            {
                for(int y = 0; y < 2*d+n+1; y++)
                {
                    for(int i = 0; i < N && double(d) >= f[i].d; i++)
                    {
                        int dx = f[i].x;
                        int dy = f[i].y;
                        int xx = x+dx;
                        int yy = y+dy;
                        if(!judge(xx, yy))
                            continue;
                        int ans;
                        if(i == 0)//(0,0)這種情況
                            ans = mp[tt][x][y];
                        else
                        {
                            int s = __gcd(abs(dx), abs(dy));
                            dx /= s;
                            dy /= s;
                            ans = Sum(tt, xx, yy, x, y, dx, dy);
                        }
                        dp[tt+1][xx][yy] = max(dp[tt][x][y]+ans, dp[tt+1][xx][yy]);
                    }
                }
            }
        }
        int Max = 0;
        for(int i = d; i < d+n; i++)
            for(int j = d; j < d+n; j++)
                if(Max < dp[max_t][i][j])
                    Max = dp[max_t][i][j];
        cout<<Max<<endl;
    }
    return 0;
}


相關文章