poj3034 Whac-a-Mole (dp)

打地鼠游戏,dp好题,麻烦的不是写出dp方程,而是求出从(x1,y1)到(x2,y2)这条直线上经过那些整数坐标,利用gcd求出来,并且需要知道的一点是中间的某个点可能跑出到矩形外面,处理跑出矩形外地点只需要扩大范围就行了,行列各增加10,让冒出地鼠的坐标响应的+5即可,dp[t][x][y]表示时刻t坐标xy出得最大个数,那么此状态可能是由上一个状态dp[t-1[i][j]转移过来的,其中(i,j)和(x,y)距离<=d,我们去所有可能的ij中的最优值,代码如下:

#include <iostream>
#include <cmath>
#include <stdio.h>
using namespace std;
int dp[11][33][33],n,d,m;
int mole[11][33][33];
int gcd ( int a, int b )
{
 return (a == 0) ? b : gcd ( b % a, a );
}
int get_sum(int x1,int y1,int x2,int y2,int t)
{
 int dx,dy,sum=0,x0,y0;
 dx=x2-x1;
    dy=y2-y1;
 if((0 == dx) && (0 == dy))
  return mole[t][x2][y2];
 if(0 == dx)
 {
  if(y1>y2)
   swap(y1,y2); 
  for(y0=y1;y0<=y2;y0++)
   sum+=mole[t][x1][y0];
  return sum;
 }
 if(0 == dy)
 {
  if(x1>x2)
   swap(x1,x2);
  for(x0=x1;x0<=x2;x0++)
   sum+=mole[t][x0][y1];
  return sum;
 }
 int g=gcd(abs(dx),abs(dy));
 dx=dx/g;
 dy=dy/g;
// for(int i=0;i<=g;i++)
//  sum+=mole[t][x1+i*dx][y1+i*dy];
 for(x0=x1,y0=y1;(x0!=x2)&&(y0!=y2);x0+=dx,y0+=dy)
  sum+=mole[t][x0][y0];
 sum+=mole[t][x0][y0];
 return sum;
}
int main()
{
 int i,j,t,tmpx,tmpy,tmpt,maxt,ii,jj,tmpSum,ans;
 while(1)
 {
  scanf("%d%d%d",&n,&d,&m);
  if(!n && !d && !m)
   break;
  maxt=0;
  ans=0;
  memset(dp,0,sizeof(dp));
  memset(mole,0,sizeof(mole));
  for(i=0;i<m;i++)
  {
   scanf("%d%d%d",&tmpx,&tmpy,&tmpt);
   if(tmpt>maxt)
    maxt=tmpt;
   mole[tmpt][tmpx+d][tmpy+d]=1;
  }
  n=n+2*d;
  for(t=1;t<=maxt;t++)
  {
   for(i=0;i<n;i++)
   {
    for(j=0;j<n;j++)
    {

     for(ii=0;ii<n;ii++)
     {
      for(jj=0;jj<n;jj++)
      {
       if(((i-ii)*(i-ii) + (j-jj)*(j-jj)) <= d*d)
       {
        tmpSum=get_sum(ii,jj,i,j,t);
       // cout<<tmpSum<<" ";
        if(dp[t-1][ii][jj]+tmpSum>dp[t][i][j])
         dp[t][i][j]=dp[t-1][ii][jj]+tmpSum;
       } 
      }
     }

    }
   }
  }
  ans=0;
  for(i=0;i<n;i++)
   for(j=0;j<n;j++)
    if(dp[maxt][i][j]>ans)
     ans=dp[maxt][i][j];
  printf("%d\n",ans);
 }
 return 0;
}

你可能感兴趣的:(poj)