ACM/ICPC 之 BFS+状态压缩(POJ1324(ZOJ1361))

Posted GUARDIAN

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ACM/ICPC 之 BFS+状态压缩(POJ1324(ZOJ1361))相关的知识,希望对你有一定的参考价值。

求一条蛇到(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 }

 

以上是关于ACM/ICPC 之 BFS+状态压缩(POJ1324(ZOJ1361))的主要内容,如果未能解决你的问题,请参考以下文章

ACM/ICPC 之 BFS范例(ZOJ2913)

POJ 4979 海贼王之伟大航路 状压dp北大ACM/ICPC竞赛训练

ACM/ICPC 之 欧拉回路两道(POJ1300-POJ1386)

ACM/ICPC 之 枚举(POJ1681-画家问题+POJ1166-拨钟问题)

ACM/ICPC 之 拓扑排序-反向(POJ3687)

ACM/ICPC 之 经典动规(POJ1088-滑雪)