思路:
继推箱子以后,又发现POJ上有这类题目,哈哈。
这次是给出一条贪食蛇当前的状态、墙的位置、食物的位置。求吃到食物需要走的最小的步数。
这类题目是相当牛逼的!高手的速度可以做到很BT的。
在 status 上面就看到有 0ms 的!相当震惊,如此庞大的数据量能做到 0ms,肯定是神牛!
后来搜了一下,还找到了那位神牛的博客,看了一下,发现看不大懂,杯具。。
哪一天有空,一定会再想一下这道题的。
一开始想了一个剪枝的方法,如果:
1. 蛇头在可以穿越蛇的身体的情况下,到达食物所用的最小步数,
2. 蛇头在不能穿越身体的情况下,到达食物所用的最小步数
这两个值相等的话,就不用继续扩展当前状态了。
一开始觉得还挺牛逼,结果一提交 TLE了,无语了。POJ 的数据真不是盖的,当然主要问题还是哥的代码太烂了。
后来改成现在这样子了。跑了1秒+。。
表示蛇的状态的时候,保存头的位置、每段身体跟前一段偏移的方向。
不然没法判重的。
#include <stdio.h>
#include <string.h>
#define QUEUE_SIZE (1 << 16)
struct node {
char y, x;
unsigned short s;
int step;
};
int N, M, L;
int hash[24][24][1 << 14], tm;
struct node queue[QUEUE_SIZE];
int head, tail;
char map[24][24];
unsigned short mask;
inline struct node input()
{
struct node t;
int y, x, i, nx, ny;
scanf("%d%d", &y, &x);
t.y = y;
t.x = x;
t.s = 0;
for (i = 0; i < L - 1; i++) {
scanf("%d%d", &ny, &nx);
if (nx == x)
t.s |= (ny < y ? 0 : 1) << (i * 2);
else
t.s |= (nx < x ? 2 : 3) << (i * 2);
y = ny;
x = nx;
}
t.step = 0;
return t;
}
inline void push(struct node t)
{
if (hash[t.y][t.x][t.s] == tm)
return ;
hash[t.y][t.x][t.s] = tm;
queue[tail++] = t;
tail &= QUEUE_SIZE - 1;
}
inline void move(struct node t, int dir)
{
int i, y, x;
y = t.y;
x = t.x;
switch (dir) {
case 0: t.y--; dir = 1; break;
case 1: t.y++; dir = 0; break;
case 2: t.x--; dir = 3; break;
case 3: t.x++; dir = 2; break;
}
if (t.y < 1 || t.y > N || t.x < 1 || t.x > M || map[t.y][t.x] == '@')
return ;
for (i = 0; i < L - 1; i++) {
switch ((t.s >> (i * 2)) & 3) {
case 0: y--; break;
case 1: y++; break;
case 2: x--; break;
case 3: x++; break;
}
if (t.y == y && t.x == x)
break;
}
if (i < L - 1)
return ;
t.s <<= 2;
t.s &= mask;
t.s |= dir;
t.step++;
push(t);
}
inline int bfs(struct node t)
{
head = tail = 0;
tm++;
push(t);
while (head != tail) {
t = queue[head++];
head &= QUEUE_SIZE - 1;
if (t.x == 1 && t.y == 1)
break;
move(t, 0);
move(t, 1);
move(t, 2);
move(t, 3);
}
return (t.x == 1 && t.y == 1) ? t.step : -1;
}
int main()
{
int y, x, c, k;
struct node t;
freopen("e:\\test\\in.txt", "r", stdin);
for (c = 1; scanf("%d%d", &N, &M), N; c++) {
memset(map, '.', sizeof(map));
scanf("%d", &L);
mask = (1 << ((L - 1) * 2)) - 1;
t = input();
scanf("%d", &k);
while (k--) {
scanf("%d%d", &y, &x);
map[y][x] = '@';
}
printf("Case %d: %d\n", c, bfs(t));
}
return 0;
}