ACM: 动态规划题 poj 3034

来源:互联网 发布:金山tw域名遭抢注 编辑:程序博客网 时间:2024/06/08 17:53
Whac-a-Mole
Description
ACM: <wbr>动态规划题 <wbr>poj <wbr>3034

While visiting a travelingfun fair you suddenly have an urge to break the high score in theWhac-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 firstconsulted the fortune teller and now you know the exact appearancepatterns of the moles.

The moles appear out of holes occupying the n2integer points (x, y) satisfying 0 ≤ x,y < n in a two-dimensional coordinatesystem. At each time step, some moles will appear and thendisappear again before the next time step. After the moles appearbut before they disappear, you are able to move your hammer in astraight line to any position (x2,y2) that is at distance at most d from yourcurrent position (x1, y1). Forsimplicity, we assume that you can only move your hammer to a pointhaving integer coordinates. A mole is whacked if the center of thehole it appears out of is located on the line between(x1, y1) and(x2, y2) (including the twoendpoints). Every mole whacked earns you a point. When the gamestarts, before the first time step, you are able to place yourhammer anywhere you see fit.

Input

The input consists ofseveral test cases. Each test case starts with a line containingthree integers n, d and m, where n andd are as described above, and m is the total numberof moles that will appear (1 ≤ n ≤ 20, 1 ≤ d ≤ 5, and1 ≤ m ≤ 1000). Then follow m lines, each containingthree integers x, y and t giving the positionand time of the appearance of a mole (0 ≤ x, y< n and 1 ≤ t ≤ 10). No two moles willappear 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 singleinteger, 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

 

题意:  打地鼠游戏, 给出地鼠出现的坐标和时间,每一秒中内打中的地鼠(xi,yi), 并且

      沿着线段一个方向打中(xj,yj), 线段长度不超过d. 计算最后能打中地鼠最大数目.

       一个地鼠一分.

解题思路:

     1. 这题状态很直接, dp[t][x][y]: 时刻t的时候, 敲打在(x,y)的得分最大值.

        状态方程:

    dp[t+1][xj][yj] = max(dp[t+1][xj][yj],dp[t][x][y]+(x,y)->(xj,yj)线段t时刻地鼠数sum);

      2.枚举时间t, 枚举二维空间(x,y), 继续在当前点(x,y)枚举四周线段(方向可以相同,长度不一).

         复杂度近似O(Tmax*n^2*方向*d).数据不大还是可以接受的.

      3.为了方便, 把全部地鼠的横纵坐标均加上d, 这样枚举四周线段时候部分线段不需要判断出界

        问题.

 

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define MAX 55
#define TIME 15

struct node
{
 int dx, dy;
 int dist;
}p[MAX*2];

int n, d, m, N, T;
int g[TIME][MAX][MAX];
int dp[TIME][MAX][MAX];
int num;

inline int max(int a, int b)
{
 return a > b ? a : b;
}

bool cmp(node &a, node &b)
{
 return a.dist < b.dist;
}

int gcd(int a, int b)
{
 return b == 0 ? a : gcd(b, a%b);
}

void init()
{
 num = 0;
 for(int i = -5; i <= 5; ++i)
 {
  for(int j = -5; j<= 5; ++j)
  {
   if(i*i + j*j<= 25)
   {
    p[num].dx= i;
    p[num].dy= j;
    p[num++].dist= ceil(sqrt(i*i+j*j+0.0));
   }
  }
 }
 sort(p, p+num, cmp);
}

inline int getSum(int t, int x, int y, int xx , int yy, int dx,int dy)
{
 int sum = 0;
 do
 {
  x += dx, y += dy;
  sum += g[t][x][y];
 }while( !(x == xx&& y == yy) );
 return sum;
}

int DP()
{
 int x, y, k, t;
 N = n+2*d;
 int sum, result = 0;
 for(t = 1; t <= T; ++t)
 {
  for(x = 0; x <N; ++x)
  {
   for(y = 0; y< N; ++y)
   {
    for(k= 0; k < num &&p[k].dist <= d; ++k)
    {
     intdx = p[k].dx;
     intdy = p[k].dy;
     intxx = x + dx;
     intyy = y + dy;
     if(xx < 0 || xx > N || yy< 0 || yy > N ) continue;
     if(p[k].dist== 0) sum = g[t][x][y];
     else
     {
      intdd = gcd(abs(dx), abs(dy));
      dx/= dd;
      dy/= dd;
      sum= g[t][x][y]+getSum(t, x, y, xx, yy, dx, dy);
     }
     dp[t+1][xx][yy]= max(dp[t+1][xx][yy], dp[t][x][y]+sum);
    }
   }
  }
 }

 for(x = d; x < n+d; ++x)
 {
  for(y = d; y <n+d; ++y)
  {
   result =max(result, dp[T+1][x][y]);
  }
 }
 return result;
}

int main()
{
 int i;
// freopen("input.txt", "r", stdin);
 init();
 while(scanf("%d %d %d",&n,&d, &m) != EOF)
 {
  if(n == 0&& d == 0&& m == 0) break;
  int x, y, t;
  T = 0;
  memset(g, 0, sizeof(g));
  memset(dp, 0,sizeof(dp));
  for(i = 0; i <m; ++i)
  {
   scanf("%d %d%d",&x, &y,&t);
   g[t][x+d][y+d]= 1;
   T = max(T,t);
  }

  printf("%d\n", DP());
 }
 return 0;
}

 

0 0
原创粉丝点击