备份备份.写不来状态压缩压缩压缩缩缩缩缩缩缩缩
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int MAX = 25;
/* N:1, E:2, S:3, W:4 */
int Move[5][2] = {0,0, -1,0, 0,1, 1,0, 0,-1};
int Move_left[5][2] = {0,0, 0,-1, -1,0, 0,1, 1,0};
int Move_right[5][2] = {0,0, 0,1, 1,0, 0,-1, -1,0};
int way_left[5] = {0, 4, 1, 2, 3};
int way_right[5] = {0, 2, 3, 4, 1};
struct Point {
int x, y;
Point(){}
Point(int a, int b):x(a), y(b) {}
bool operator==(const Point& B)const {
return x == B.x && y == B.y;
}
} E(1, 1); //E:终点
/* 根据蛇身两个点,返回第二个点相对第一个点的相对位置 */
/* N:1 E:2 S:3 W:4 */
int Next(int x, int y, int tx, int ty) {
if (x == tx) {
if (ty > y) return 2;
return 4;
} else {
if (tx > x) return 3;
return 1;
}
}
struct Snake:public Point {
int to; //x,y,to -> head
int steps; //步数
int status; //状态,每个状态对应一个至多7位的4进制数,为0~4^8-1;
/* 状态描述为头坐标,然后是身子的每个点与上一个点的相对位置 */
/* 实际上只需要3个方向 */
/* 长度就不在这里描述了,反正题目会给出来 */
Snake() {status = 0;}
/* 获得蛇的当前状态 */
vector<Point> getStatus(void) {
/* 解码,返回蛇身子的每个点坐标 */
vector<Point> res;
Point p(x, y);
res.push_back(p);
while (status) {
int ft = status % 5;
status /= 5;
p.x += Move[ft][0], p.y += Move[ft][1];
res.push_back(p);
}
return res;
}//getStatus
/* 设置状态,根据pos指定的点坐标,还原蛇的状态. */
void setStatus(vector<Point> pos) {
status = 0;
x = pos[0].x, y = pos[0].y;
int &t = status, tmp; ///啦啦啦
t = 0;
for (int i = pos.size()-1; i > 0; --i) {
tmp = Next(pos[i-1].x, pos[i-1].y, pos[i].x, pos[i].y);
t *= 5;
t += tmp;
}
tmp = Next(pos[0].x, pos[0].y, pos[1].x, pos[1].y);
to = (tmp+2)%4 == 0 ? 4 : (tmp+2)%4;
}
/* 蛇前进一步 */
void Forward(void) {
/* 蛇头前进一步,身子呢?身子其实奏是走到它前面那个点就OK了 */
vector<Point> pos = getStatus();
for (int i = pos.size()-1; i > 0; --i) {
pos[i].x = pos[i-1].x, pos[i].y = pos[i-1].y;
}
pos[0].x += Move[to][0], pos[0].y += Move[to][1];
setStatus(pos);
}
/* 向左走一步 */
void Left(void) {
/* 类同上述,蛇头左走一步,身子挪到前一个位置 */
vector<Point> pos = getStatus();
for (int i = pos.size()-1; i > 0; --i) {
pos[i].x = pos[i-1].x, pos[i].y = pos[i-1].y;
}
pos[0].x += Move_left[to][0], pos[0].y += Move_left[to][1];
setStatus(pos);
}
/* 向右走一步 */
void Right(void) {
vector<Point> pos = getStatus();
for (int i = pos.size()-1; i > 0; --i) {
pos[i].x = pos[i-1].x, pos[i].y = pos[i-1].y;
}
pos[0].x += Move_right[to][0], pos[0].y += Move_right[to][1];
setStatus(pos);
}
} snake;
int n, m, K, L;
bool Map[MAX][MAX];
bool vis[MAX][MAX][5];
vector<Point> body;
void exChange(void) {
snake.x = body[0].x;
snake.y = body[0].y;
snake.steps = 0;
int &t = snake.status, tmp; ///啦啦啦
t = 0;
for (int i = L-1; i > 0; --i) {
tmp = Next(body[i-1].x, body[i-1].y, body[i].x, body[i].y);
t *= 5;
t += tmp;
}
tmp = Next(body[0].x, body[0].y, body[1].x, body[1].y); //召唤出第一节身子在头的甚么方向
snake.to = (tmp+2)%4 == 0 ? 4 : (tmp+2)%4;//1->3, 2->4, 3->1, 4->2.第一节身子在头的南方,头就朝向北,其他方向类同
//printf("way: %d\n", snake.to);
}
bool check(int x, int y) {
return x > 0 && y > 0 && x <= n && y <= m
&& Map[x][y];
}
bool judge(Snake s, int x, int y) {
/* 题目说明是蛇头先动,完了后身子再前移.
* 所以这里很关键,判据不能丢
*/
Point p(x, y);
vector<Point> tmp = s.getStatus();
//printf("receive: %d,%d\n", x, y);
//bool PRINT = (x == 5 && y == 2);
//if (PRINT) puts("warning!......");
for (int i = 0; i < tmp.size(); ++i) {
//if (PRINT) {
//printf("judge %d,%d...", tmp[i].x, tmp[i].y);
//}
if (tmp[i] == p) {
//if (PRINT) printf("Failed\n");
return false;
}
//if (PRINT) puts("ok");
}
return true;
}
/* BFS,每次压入一只蛇,包含了它的状态.搜下一层时其一不能撞到石头或越界,
* 其二不能撞到身子,用judge函数来判断(二),用check函数来检查(一)
*/
int BFS(void) {
memset(vis, false, sizeof(vis));
Point tmp;
queue<Snake> Q;
Snake now, next;
Q.push(snake); //初始
while (!Q.empty()) {
now = Q.front(); Q.pop();
if (now == E) return now.steps;
//枚举三个状态:蛇头向前,向左,向右
/* forward */
next = now; next.steps++;
tmp.x = now.x + Move[next.to][0];
tmp.y = now.y + Move[next.to][1];
if (check(tmp.x, tmp.y) && !vis[tmp.x][tmp.y][next.to] && judge(now, tmp.x, tmp.y)) {
next.Forward();
Q.push(next);
//printf("Push1: (%d,%d,%d,%d)\n", next.x, next.y, next.to, next.steps);
//getchar();
vis[next.x][next.y][next.to] = true;
}
/* left */
next = now; next.steps++;
tmp.x = now.x + Move_left[now.to][0];
tmp.y = now.y + Move_left[now.to][1];
//puts("warning");
//printf("%d,%d -> %d,%d\n", now.x, now.y, tmp.x, tmp.y);
if (check(tmp.x, tmp.y) && !vis[tmp.x][tmp.y][way_left[now.to]] && judge(now, tmp.x, tmp.y)) {
//puts("flag2");
//printf("now = %d,%d,%d\n", now.x, now.y, now.to);
next.Left();
Q.push(next);
//printf("Push2: (%d,%d,%d,%d)\n", next.x, next.y, next.to, next.steps);
//getchar();
vis[next.x][next.y][next.to] = true;
}
/* right */
next = now; next.steps++;
tmp.x = now.x + Move_right[now.to][0];
tmp.y = now.y + Move_right[now.to][1];
if (check(tmp.x, tmp.y) && !vis[tmp.x][tmp.y][way_right[now.to]] && judge(now, tmp.x, tmp.y)) {
next.Right();
Q.push(next);
//printf("Push3: (%d,%d,%d,%d)\n", next.x, next.y, next.to, next.steps);
//getchar();
vis[next.x][next.y][next.to] = true;
}
//static int _t = 0;
//printf("%d\n", ++_t);
//puts("flag");
}
return -1;
}
int main() {
while (~scanf(" %d %d %d", &n, &m, &L) && L) {
memset(Map, true, sizeof(Map));
body.resize(L+1);
for (int i = 0; i < L; ++i) {
scanf(" %d %d", &body[i].x, &body[i].y);
}
scanf(" %d", &K);
int x, y;
for (int i = 0; i < K; ++i) {
scanf(" %d %d", &x, &y);
Map[x][y] = false;
}
exChange();
static int cas = 0;
printf("Case %d: %d\n", ++cas, BFS());
}
return 0;
}