poj-3034 Whac-a-Mole
2011-07-09 16:52
405 查看
dp
先自己写了一个。。 n次WA后搞成TLE~ 。。。 忍无可忍。。 后来参考了网上的代码。 最终AC~
先贴人家的代码吧~
【转】
思路:DP。改了要一天,很纠结的一道题。DP部分,dp[t][x][y]表示第t时间把锤子停在(x,y)上最多能够打到的地鼠数量。则dp[t][x][y]
= max(dp[t-1][xx][yy]
+ (xx,yy)到点(x,y)新打的地鼠数),(xx,yy)和(x,y)的直线距离<d。但是最主要的是下面两点:
1:中转点可能在区域外,如下数据: //相当重要!!!
20 5 4
1 0 1
0 1 1
0 5 2
1 6 2
答案应该是4而不是3,这就需要扩展区域为n+2d就够啦。
2:(xx,yy)到点(x,y)新打的地鼠数的求法。这点纠结了很久,若一个点在线段(xx,yy)(x,y)上,则这一点上面的地鼠也会被打到。还是看代码吧....
源代码:(464K,563MS)
#include<iostream>
#include<cmath>
#include<algorithm>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
struct data{
int dx, dy,
dw;
}ste[100];
int n, N, d, m, k;
int dp[15][50][50];
int map[15][50][50];
bool cmp(data a, data b){
return a.dw
< b.dw;
}
bool inMap(int x, int y){
if(x
>= 0 && x
<= N && y
>= 0 && y
<= N) return true;
return
false;
}
int gcd(int a, int b){ //最大公因数
if(b ==
0) return a;
return
gcd(b, a%b);
}
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 += map[t][x][y];
}while(!(x
== xx && y == yy));
return
sum;
}
int main(){
int t, i, T,
sum;
int x, y,
xx, yy, dx, dy;
for(k = 0, x
= -5; x <= 5; x
++)
// 先预处理5步内所有可能的走法。(d<=5)
for(y = -5; y <= 5; y ++)
if(x*x + y*y <= 25){
ste[k].dx = x;
ste[k].dy = y;
ste[k ++].dw = ceil(sqrt(0.0+x*x+y*y));
}
sort(ste,
ste+k, cmp);
while(scanf("%d%d%d", &n, &d,
&m) && n){
memset(dp, 0, sizeof(dp));
memset(map, 0, sizeof(map));
T = -1;
while(m --){
scanf("%d%d%d", &x, &y,
&t);
map[t][x+d][y+d] = 1;
T = max(T, t);
}
T ++, N = n+2*d;
// 扩展区域。
for(t = 1; t < T; t ++)
for(x = 0; x <= N; x ++)
for(y = 0; y <= N; y ++)
for(i = 0; ste[i].dw <= d
&& i < k; i
++){
dx = ste[i].dx;
dy = ste[i].dy;
xx = x + dx;
yy = y + dy;
if(!inMap(xx, yy)) continue;
if(i == 0) sum = map[t][x][y];
else{
// 求(xx,yy)到(x,y)线段上能打到的地鼠数,gcd()用得很巧。
int tmp = gcd(abs(dx), abs(dy));
dx = dx / tmp;
dy = dy / tmp;
sum = map[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);
}
int ans = 0;
for(x = d; x < n+d; x ++)
for(y = d; y < n+d; y ++)
ans = max(ans, dp[T][x][y]);
printf("%d\n", ans);
}
return
0;
}
最后贴上我的TLE代码~
思路一样。。 只是处理点是否在直线上的方式不同。。
/*
* 3034.cpp
*
* Created on: 2011-7-9
* Author:
*/
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const double eps = 1e-6;
int n, d, m;
int dp[1000 + 5][50 + 5][ 50 + 5] = {};
int p[1000 + 5][50 + 5][50 + 5] = {}; //mole的情况
int main(){
while(true){
//输入
scanf("%d%d%d", &n, &d, &m);
if(n == 0) return 0;
memset(dp, 0, sizeof(dp));
memset(p, 0, sizeof(p));
int max_t = -1, _x, _y, _t;
for(int i=0; i<m; i++){
scanf("%d%d%d", &_x, &_y, &_t);
_x += d; _y += d;
p[_t][_x][_y] = 1;
if(max_t < _t) max_t = _t;
}
//……
for(int it=1; it<=max_t; it++){
for(int ix=0; ix<=n+2*d; ix++){
for(int iy=0; iy<=n+2*d; iy++){
for(int ixx=0; ixx<=n+2*d; ixx++){
for(int iyy=0; iyy<=n+2*d; iyy++){
if(ixx != ix && (ixx - ix) * (ixx - ix) + (iyy - iy) * (iyy - iy) <= d * d){
double k = ((double)iyy - iy) / (ixx - ix); //斜率, 要求ixx!=ix
int dx = (ixx > ix ? -1 : 1);
int dy = (iyy > iy ? -1 : 1);
int tmp_mole = dp[it-1][ixx][iyy];
for(int gx=ixx; gx!=ix+dx; gx+=dx){ //iyy 可以 = iy
for(int gy=iyy; gy!=iy+dy; gy+=dy){
// if(fabs(k * (gx - ix) - gy + iy) <= eps){ //这样的话WA~
if(((double)gy - iy) / (gx - ix) - k <= eps && (gx-ix)*(gx-ixx) <= 0){ // 斜率相等且点在起点和终点之间 TLE 囧~
tmp_mole += p[it][gx][gy];
}
}
}
if(dp[it][ix][iy] < tmp_mole)
dp[it][ix][iy] = tmp_mole;
}
else if(ixx == ix && iyy - iy <= d){ //ixx == ix 的情况
int dy = (iyy > iy ? -1 : 1);
int tmp_mole = dp[it-1][ixx][iyy];
for(int gy=iyy; gy!=iy+dy; gy+=dy){
if(p[it][ix][gy]) tmp_mole++;
}
if(dp[it][ix][iy] < tmp_mole)
dp[it][ix][iy] = tmp_mole;
}
}
}
}
}
}
int ans = -1;
for(int i=d; i<n+d; i++){
for(int j=d; j<n+d; j++){
if(dp[max_t][i][j] > ans)
ans = dp[max_t][i][j];
}
}
printf("%d\n", ans);
}
return 0;
}
先自己写了一个。。 n次WA后搞成TLE~ 。。。 忍无可忍。。 后来参考了网上的代码。 最终AC~
先贴人家的代码吧~
【转】
思路:DP。改了要一天,很纠结的一道题。DP部分,dp[t][x][y]表示第t时间把锤子停在(x,y)上最多能够打到的地鼠数量。则dp[t][x][y]
= max(dp[t-1][xx][yy]
+ (xx,yy)到点(x,y)新打的地鼠数),(xx,yy)和(x,y)的直线距离<d。但是最主要的是下面两点:
1:中转点可能在区域外,如下数据: //相当重要!!!
20 5 4
1 0 1
0 1 1
0 5 2
1 6 2
答案应该是4而不是3,这就需要扩展区域为n+2d就够啦。
2:(xx,yy)到点(x,y)新打的地鼠数的求法。这点纠结了很久,若一个点在线段(xx,yy)(x,y)上,则这一点上面的地鼠也会被打到。还是看代码吧....
源代码:(464K,563MS)
#include<iostream>
#include<cmath>
#include<algorithm>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
struct data{
int dx, dy,
dw;
}ste[100];
int n, N, d, m, k;
int dp[15][50][50];
int map[15][50][50];
bool cmp(data a, data b){
return a.dw
< b.dw;
}
bool inMap(int x, int y){
if(x
>= 0 && x
<= N && y
>= 0 && y
<= N) return true;
return
false;
}
int gcd(int a, int b){ //最大公因数
if(b ==
0) return a;
return
gcd(b, a%b);
}
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 += map[t][x][y];
}while(!(x
== xx && y == yy));
return
sum;
}
int main(){
int t, i, T,
sum;
int x, y,
xx, yy, dx, dy;
for(k = 0, x
= -5; x <= 5; x
++)
// 先预处理5步内所有可能的走法。(d<=5)
for(y = -5; y <= 5; y ++)
if(x*x + y*y <= 25){
ste[k].dx = x;
ste[k].dy = y;
ste[k ++].dw = ceil(sqrt(0.0+x*x+y*y));
}
sort(ste,
ste+k, cmp);
while(scanf("%d%d%d", &n, &d,
&m) && n){
memset(dp, 0, sizeof(dp));
memset(map, 0, sizeof(map));
T = -1;
while(m --){
scanf("%d%d%d", &x, &y,
&t);
map[t][x+d][y+d] = 1;
T = max(T, t);
}
T ++, N = n+2*d;
// 扩展区域。
for(t = 1; t < T; t ++)
for(x = 0; x <= N; x ++)
for(y = 0; y <= N; y ++)
for(i = 0; ste[i].dw <= d
&& i < k; i
++){
dx = ste[i].dx;
dy = ste[i].dy;
xx = x + dx;
yy = y + dy;
if(!inMap(xx, yy)) continue;
if(i == 0) sum = map[t][x][y];
else{
// 求(xx,yy)到(x,y)线段上能打到的地鼠数,gcd()用得很巧。
int tmp = gcd(abs(dx), abs(dy));
dx = dx / tmp;
dy = dy / tmp;
sum = map[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);
}
int ans = 0;
for(x = d; x < n+d; x ++)
for(y = d; y < n+d; y ++)
ans = max(ans, dp[T][x][y]);
printf("%d\n", ans);
}
return
0;
}
最后贴上我的TLE代码~
思路一样。。 只是处理点是否在直线上的方式不同。。
/*
* 3034.cpp
*
* Created on: 2011-7-9
* Author:
*/
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const double eps = 1e-6;
int n, d, m;
int dp[1000 + 5][50 + 5][ 50 + 5] = {};
int p[1000 + 5][50 + 5][50 + 5] = {}; //mole的情况
int main(){
while(true){
//输入
scanf("%d%d%d", &n, &d, &m);
if(n == 0) return 0;
memset(dp, 0, sizeof(dp));
memset(p, 0, sizeof(p));
int max_t = -1, _x, _y, _t;
for(int i=0; i<m; i++){
scanf("%d%d%d", &_x, &_y, &_t);
_x += d; _y += d;
p[_t][_x][_y] = 1;
if(max_t < _t) max_t = _t;
}
//……
for(int it=1; it<=max_t; it++){
for(int ix=0; ix<=n+2*d; ix++){
for(int iy=0; iy<=n+2*d; iy++){
for(int ixx=0; ixx<=n+2*d; ixx++){
for(int iyy=0; iyy<=n+2*d; iyy++){
if(ixx != ix && (ixx - ix) * (ixx - ix) + (iyy - iy) * (iyy - iy) <= d * d){
double k = ((double)iyy - iy) / (ixx - ix); //斜率, 要求ixx!=ix
int dx = (ixx > ix ? -1 : 1);
int dy = (iyy > iy ? -1 : 1);
int tmp_mole = dp[it-1][ixx][iyy];
for(int gx=ixx; gx!=ix+dx; gx+=dx){ //iyy 可以 = iy
for(int gy=iyy; gy!=iy+dy; gy+=dy){
// if(fabs(k * (gx - ix) - gy + iy) <= eps){ //这样的话WA~
if(((double)gy - iy) / (gx - ix) - k <= eps && (gx-ix)*(gx-ixx) <= 0){ // 斜率相等且点在起点和终点之间 TLE 囧~
tmp_mole += p[it][gx][gy];
}
}
}
if(dp[it][ix][iy] < tmp_mole)
dp[it][ix][iy] = tmp_mole;
}
else if(ixx == ix && iyy - iy <= d){ //ixx == ix 的情况
int dy = (iyy > iy ? -1 : 1);
int tmp_mole = dp[it-1][ixx][iyy];
for(int gy=iyy; gy!=iy+dy; gy+=dy){
if(p[it][ix][gy]) tmp_mole++;
}
if(dp[it][ix][iy] < tmp_mole)
dp[it][ix][iy] = tmp_mole;
}
}
}
}
}
}
int ans = -1;
for(int i=d; i<n+d; i++){
for(int j=d; j<n+d; j++){
if(dp[max_t][i][j] > ans)
ans = dp[max_t][i][j];
}
}
printf("%d\n", ans);
}
return 0;
}
相关文章推荐
- poj 3034 Whac-a-Mole
- POJ 3034 Whac-a-Mole [DP]
- POJ-3034 Whac-a-Mole 动态规划
- poj3034--Whac-a-Mole(dp)
- (中等) POJ 3034 Whac-a-Mole,DP。
- POJ 3034 Whac-a-Mole(三维dp+处理小技巧)
- poj 3034 Whac-a-Mole
- POJ 3034 Whac-a-Mole(DP)
- poj 3034 Whac-a-Mole 动态规划,线段上点个数
- poj_3034 Whac-a-Mole(dp)
- poj 3034 Whac-a-Mole(dp)
- POJ 3034 Whac-a-Mole
- poj&nbsp;3034&nbsp;Whac-a-Mole&nbsp;dp
- POJ 3034 Whac-a-Mole
- POJ 3034 Whac-a-Mole
- poj 3034 Whac-a-Mole
- poj 3034 Whac-a-Mole
- POJ 3034 Whac-a-Mole
- 【POJ 3034】 Whac-a-Mole(DP)
- POJ 3034 Whac-a-Mole