打地鼠游戏,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;
}