• 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
    ");
     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
    ", 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
    ");
     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 }
    他坐在湖边,望向天空,她坐在对岸,盯着湖面
  • 相关阅读:
    iOS崩溃报告获取一
    GCDTimer
    Runtime
    Socket
    冒泡排序笔记
    学习java虚拟机笔记
    ftp发送文件包括中文名
    java email
    批量数据插入高效 转发
    读取本地硬盘文件,快速扫描插入 数据库
  • 原文地址:https://www.cnblogs.com/Inkblots/p/5339371.html
Copyright © 2020-2023  润新知