求一条蛇到(1,1)的最短路长,题目不简单,状态较多,需要考虑状态压缩,ZOJ的数据似乎比POj弱一些
POJ1324(ZOJ1361)-Holedox Moving
题意:一条已知初始状态的蛇,求其到(1,1)的最短路长
题解:开始做的时候用BFS暴力做了一次,结果RE了,后来看了其他的题解和discuss才转向状态压缩。也看到有人用A*做出来了。
现在简要介绍一下状态压缩的思路:
由于蛇身最长只有8,可以利用两条相邻蛇身坐标确定其相对方向(四个方向),两位二进制可以表示
这样 一个蛇头坐标+14位二进制数 就可以确定一个蛇身状态
而后状态重复则可以进行剪枝,这是一种很好的优化。
这里我用一个方向数组mov[4][2]简化代码,而且不需要自己考虑太多方向的先后顺序及分支。
1 //蛇的移动-求达到终点的最短路长 2 //BFS+状态压缩 3 //两位二进制(4个方向)记录后一个蛇身相对前一个的位置,以此将蛇身记录为数值 4 //POJ:Time: 1297Ms Memory: 25440K 5 //ZOJ:Time: 350Ms Memory: 31388K 6 #include<iostream> 7 #include<cstring> 8 #include<cstdio> 9 using namespace std; 10 const int MAX = 22; 11 const int MAXN = 1000000; 12 const int MAXLEN = 1 << 14 + 1; 13 struct Snake{ 14 int x, y; 15 }snake[10]; 16 struct State { 17 Snake h; //头部坐标 18 unsigned hash; 19 int step; 20 }s[MAXN]; 21 int row, col, len; 22 bool map[MAX][MAX]; //是否存在障碍 23 bool v[MAX][MAX][MAXLEN]; //状态记录 24 int mov[4][2] = { {1,0}, {-1,0}, {0,1}, {0,-1} }; 25 int get_next_hash(int hash, Snake pre, Snake next) 26 { 27 const int INF = (1 << ((len - 1) << 1)) - 1; 28 int dx = pre.x - next.x; 29 int dy = pre.y - next.y; 30 for (int i = 0; i < 4; i++) 31 { 32 if (mov[i][0] == dx && mov[i][1] == dy) 33 { 34 hash <<= 2; 35 hash &= INF; 36 hash |= i; 37 break; 38 } 39 } 40 return hash; 41 } 42 /*是否撞到自己或障碍*/ 43 bool judge(State cur, Snake t) 44 { 45 if (t.x > 0 && t.x <= row && t.y > 0 && t.y <= col && !map[t.x][t.y]) 46 { 47 for (int i = 1; i < len; i++) 48 { 49 int key = (1 << 2) - 1; 50 key &= cur.hash; 51 cur.hash >>= 2; 52 cur.h.x += mov[key][0]; 53 cur.h.y += mov[key][1]; 54 if (cur.h.x == t.x && cur.h.y == t.y) //撞到了 55 return false; 56 } 57 return true; 58 } 59 return false; 60 } 61 void bfs() 62 { 63 int front = 0, tail = 1; 64 s[0].step = 0; 65 if (s[0].h.x == 1 && s[0].h.y == 1) 66 { 67 printf("0\n"); 68 return; 69 } 70 while (front < tail) 71 { 72 for (int i = 0; i < 4; i++) 73 { 74 Snake t; 75 t.x = s[front].h.x + mov[i][0]; 76 t.y = s[front].h.y + mov[i][1]; 77 if (t.x == 1 && t.y == 1) 78 { 79 printf("%d\n", s[front].step + 1); 80 return; 81 } 82 if (judge(s[front], t)) 83 { 84 s[tail].hash = get_next_hash(s[front].hash, s[front].h, t); 85 if (!v[t.x][t.y][s[tail].hash]) 86 { 87 v[t.x][t.y][s[tail].hash] = true; 88 s[tail].h = t; 89 s[tail].step = s[front].step + 1; 90 tail++; 91 } 92 } 93 } 94 front++; 95 } 96 printf("-1\n"); 97 } 98 //初始化蛇的开始位置 99 void init_snake() 100 { 101 s[0].h = snake[0]; 102 s[0].hash = 0; 103 for (int i = len - 1; i > 0; i--) 104 s[0].hash = get_next_hash(s[0].hash, snake[i], snake[i - 1]); 105 v[s[0].h.x][s[0].h.y][s[0].hash] = true; 106 } 107 int main() 108 { 109 int counter = 0; 110 while (scanf("%d%d%d", &row, &col, &len), row && col && len) 111 { 112 memset(map, false, sizeof(map)); 113 memset(v, false, sizeof(v)); 114 for (int i = 0; i < len; i++) 115 scanf("%d%d", &snake[i].x, &snake[i].y); 116 int m, x, y; 117 scanf("%d", &m); 118 for (int i = 0; i < m; i++) 119 { 120 scanf("%d%d", &x, &y); 121 map[x][y] = true; 122 } 123 init_snake(); 124 printf("Case %d: ", ++counter); 125 bfs(); 126 } 127 return 0; 128 }