您的位置:首页 > 其它

USACO 3.3 Camelot

2013-01-11 00:10 260 查看
题意:

在R行C列的棋盘上(R<=30,C<=26),有互相不重叠的若干个骑士和王,骑士可以按照马的方式走,王可以走周围的八个位置。

骑士和王到达一个点的时候骑士可以接王。

问:最少经过多少步能够让所有的棋子到达同一格。

思路:

首先棋盘的每两点之间的骑士最短距离可以通过R*C次BFS得到。

考虑暴力枚举:

for 集合点(R*C)

for 接王的骑士(R*C)

for 接王的点(R*C)

算出距离

这样,复杂度达到了O((R*C)^3),必然超时,于是想方设法进行剪枝。

考虑以下几种剪枝方式:(无证明。。。来自From北极星天南)

1)由于王总是比骑士走得慢,所以接王的点一定靠近王(在王的某个范围内)。

2)在枚举集合点的时候,如果所有的骑士到达该点的距离和已经大于当前答案,那么不许进行后面的枚举

3)当骑士较多时,集合点在骑士们的中心附近(骑士均值坐标的某个范围内)。

注意:

交了很多次才过。

1)读入数据的时候,纵坐标可能是两位的数字,不是单个字符,但是横坐标就是单个字符

2)x对应的是column,y对应的是row

3)可能存在不能到达的两个点,所以所有的dist[][][][]要初始化为INF而不是0

4)王一步可以到达周围八个点,所以当王从a,b 到c,d 的最小步数是max(abs(a,b),abs(c-d))

5)只有一个王单独处理,答案是0

Executing...
Test 1: TEST OK [0.000 secs, 7476 KB]
Test 2: TEST OK [0.000 secs, 7476 KB]
Test 3: TEST OK [0.000 secs, 7476 KB]
Test 4: TEST OK [0.011 secs, 7476 KB]
Test 5: TEST OK [0.065 secs, 7476 KB]
Test 6: TEST OK [0.065 secs, 7476 KB]
Test 7: TEST OK [0.000 secs, 7476 KB]
Test 8: TEST OK [0.011 secs, 7476 KB]
Test 9: TEST OK [0.032 secs, 7476 KB]
Test 10: TEST OK [0.065 secs, 7476 KB]
Test 11: TEST OK [0.000 secs, 7476 KB]
Test 12: TEST OK [0.000 secs, 7476 KB]
Test 13: TEST OK [0.000 secs, 7476 KB]
Test 14: TEST OK [0.000 secs, 7476 KB]
Test 15: TEST OK [0.000 secs, 7476 KB]
Test 16: TEST OK [0.000 secs, 7476 KB]
Test 17: TEST OK [0.000 secs, 7476 KB]
Test 18: TEST OK [0.000 secs, 7476 KB]
Test 19: TEST OK [0.000 secs, 7476 KB]
Test 20: TEST OK [0.000 secs, 7476 KB]

代码:

/*
ID: jasison2
LANG: C++
TASK: camelot
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define N 32
#define INF 0x7fffffff
#define MAX(a,b) (a)<(b)?(b):(a)
#define MIN(a,b) (a)<(b)?(a):(b)
inline int ABS(int x) { return x<0 ? -x : x; }

int r, c, n;
int dist

; // distance with knight
bool vis

;
int p[N*N][2]; // king and knight position
int dx, dy; // gather position
int dir[8][2] = {{-2,-1},{-2,1},{-1,-2},{-1,2},{1,2},{1,-2},{2,-1},{2,1}};
struct Point
{
int x, y;
Point() {}
Point(int _x, int _y): x(_x), y(_y){}
bool legal() { return x>0 && x<=c && y>0 && y<=r && !vis[x][y]; }
void visit() { vis[x][y] = true; }
};
inline void input()
{
cin >> r >> c;
n = 0;
char x;
dx = dy = 0;
while (cin >> x >> p
[1])
{
p
[0] = x - 'A' + 1;
if (n)
{
dx += p
[0];
dy += p
[1];
}
n ++;
}
if (n > 1)
{
dx /= (n-1);
dy /= (n-1);
}
}
void bfs()
{
Point cur, nxt;
for (int i = 1; i <= c; ++ i)
{
for (int j = 1; j <= r; ++ j)
{
for (int ix = 1; ix <= c; ++ ix)
for (int iy = 1; iy <= r; ++ iy)
dist[i][j][ix][iy] = 100;
memset(vis, false, sizeof(vis));
queue <Point> Q;
Q.push(Point(i,j));
vis[i][j] = true;
dist[i][j][i][j] = 0;
while (!Q.empty())
{
cur = Q.front();
Q.pop();
for (int k = 0; k < 8; ++ k)
{
nxt = Point(cur.x+dir[k][0], cur.y+dir[k][1]);
if (nxt.legal())
{
dist[i][j][nxt.x][nxt.y] = dist[i][j][cur.x][cur.y] + 1;
nxt.visit();
Q.push(nxt);
}
}
}
}
}
}
int calc()
{
if (n == 1) return 0;
int ans = INF;
int sdx, sdy, edx, edy, sx, sy, ex, ey;
if (n < 3)
{
sdx = sdy = 1;
edx = c; edy = r;
}
else
{
sdx = MAX(1,dx-2); sdy = MAX(1,dy-2);
edx = MIN(c,dx+2); edy = MIN(r,dy+2);
}
sx = MAX(1,p[0][0]-2); sy = MAX(1,p[0][1]-2);
ex = MIN(c,p[0][0]+2); ey = MIN(r,p[0][1]+2);
for (dx = sdx; dx <= edx; ++ dx)
{
for (dy = sdy; dy <= edy; ++ dy)
{
int tans = 0;
for (int k = 1; k < n; ++ k)
tans += dist[p[k][0]][p[k][1]][dx][dy];
if (tans > ans) continue;
for (int k = 1; k < n; ++ k)
{
tans -= dist[p[k][0]][p[k][1]][dx][dy];
for (int x = sx; x <= ex; ++ x)
{
for (int y = sy; y <= ey; ++ y)
{
tans += dist[p[k][0]][p[k][1]][x][y] + dist[x][y][dx][dy];
tans += MAX(ABS(x-p[0][0]), ABS(y-p[0][1]));
if (tans < ans) ans = tans;
tans -= dist[p[k][0]][p[k][1]][x][y] + dist[x][y][dx][dy];
tans -= MAX(ABS(x-p[0][0]), ABS(y-p[0][1]));
}
}
tans += dist[p[k][0]][p[k][1]][dx][dy];
}
}
}
return ans;
}
void output()
{
printf("%d\n", calc());
}
int main()
{
freopen("camelot.in","r",stdin);
freopen("camelot.out","w",stdout);
input();
bfs();
output();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: