[迭代加深 A *] Palamaze (皇宫VS迷宫)

来源:互联网 发布:众途软件 编辑:程序博客网 时间:2024/04/29 04:34
皇宫VS迷宫(palamaze)问题描述  FISH社会还是封建制度,皇帝是最高统治者,皇宫作为皇帝吃喝完乐的场所,警卫森严,一般人一旦进入,就很难活着出来。与其说它是个皇宫,还不如说他是个迷宫。这个巨大的迷宫花费了无数蠢得要死的FISH的辛勤劳动建成,因此结构极其复杂,而且到处机关重重。首先它是由N*M个格子构成的矩形区域。有的格子是石头,无法穿越(黄色部分);而有的格子是水(白色部分),水中如果没有管道(彩色长条),则FISH可以在里面自由泳;但在一些水中可能存在连接上下或左右两个格子的管道,FISH不能逗留在有管道的格子里,但是可以从一个纵向的管道的下面那个格子、穿过这个管道、游到管道上面的那个格子,前提是这两个格子都不是石头。同样也可以反过来游,横向的管道也是类似的。任何管道所在格子都不相邻。某些格子中还存放有一些管道的钥匙,一旦得到某片钥匙时,就可以改变与之对应的管道(图中颜色相等)的方向,前提是先游到管道所在格的相邻格子(上下左右共边的格子为相邻格)。一旦FISH游到一个格子,FISH就会用最快速度搜寻一遍这个格子和上下左右相邻的格子,然后把在格中找到的钥匙当作宝贝一样的吞进肚子里(要用的时候再吐出来)。一个格子中可能没有钥匙,但不可能有多片钥匙。迷宫中仅存在一个出口,FISH到那一格就可以重见天日。如果有钥匙,旋转管道是十分快捷的,四肢发达的FISH(虽然似乎没有四肢)将不费吹灰之力迅速的改变某个管道的方向,前提是获得了那个管道的对应钥匙。每一个时刻FISH可以从一个格子游到上下左右相邻的另一个格子(前提:不能游到石头里,也不能有管道),或者穿过某个相邻格的管道达到一个距离为2的格子(上上、下下、左左、右右4个格子),当然也不能为石头或管道。为了防止其他进入迷宫的人探索出迷宫的出路,迷宫有一种高级自动关闭系统,当它检测到一条FISH进入到迷宫中时,迷宫会自动从0开始计时。当计到10000后,迷宫会自动关闭,里面的一切生灵(包括FISH算了)都无逃逸的可能了——所以一旦进入迷宫,必须在最少的步数内逃离!否则,嘿嘿~ 死得你一瞧起。虽然很多人对FISH的死将无动于衷,更有甚者将会幸灾乐祸,但是作为一个正直、智慧、无私、伟大、光明、圣洁的人,你觉得应该为FISH做点什么,比如告诉他:至少需要多少时刻才能逃离迷宫(FISH不要高兴的太早,反正告诉了步数你也不一定能够逃出来的)。输入文件(palamaze.in)第一行两个数n,m。(n,m<=20)表示n行m列接下来。N行m列的矩阵。‘*’表示障碍‘+’表示正常的路‘#’表示起点‘$’表示终点数字表示钥匙,大写字母表示桥横放,小写字母表示桥竖放不超过9对字母其中1对应a,A依次类推输出文件(palamaze.out)一行,表示最小步数。如果不能逃出,输出10001。样例输入4 4*****#+**+$*****样例输出2

初次看到这道题不晓得状态是什么,以为如果要广搜的话,要把整个地图都压进去,压位也会挂空间,于是就写了迭代加深 A *,然后加了一点小优化卡深度,骗了 60 分,感觉还可以的样子。
后来听 ccl 说,只要一个坐标和钥匙集合就可以描述一个状态了。想想也对:之所以觉得要压整个图,就是觉得管道的翻转需要被记。但是如果有了钥匙,随他管道是什么样子都可以过;如果没有钥匙,管道顺着方向可以过,逆着就不可以了。也就是说,如果没有钥匙,管道不变;有钥匙就可以无视管道。所以这道题的状态其实是三维的:x, y, z, 分别表示坐标和钥匙集合。
然后因为不想写广搜了,所以写了 ID,顺便加了个 A *,但感觉优化力度不太大,可能是因为图上很多障碍物而没有什么空旷处之类吧。
再者,为了避免转圈圈而导致解非最优,每次松弛一下一个点的最短路径即可。为了避免清空数组,我写了时间戳。
Code : 

#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#define swap(a, b, t) ({t _ = (a); (a) = (b); (b) = _;})#define max(a, b) ({int _ = (a), __ = (b); _ > __ ? _ : __;})#define min(a, b) ({int _ = (a), __ = (b); _ < __ ? _ : __;})const int dx[5] = {0, 0, - 1, 0, 1};const int dy[5] = {0, - 1, 0, 1, 0};int n, m, x1, y1, x2, y2, lim;char a[22][22];bool b[22][22];int c[22][22], d[22][22], e[22][22];int f[22][22][1005], g[22][22][1005];int getdist(int x, int y){     if ((x -= x2) < 0) x = - x;     if ((y -= y2) < 0) y = - y;     return x + y + 1 >> 1;}bool okay(int dep, int x, int y, int z){     if (g[x][y][z] < lim || g[x][y][z] == lim && dep < f[x][y][z])          return f[x][y][z] = dep, g[x][y][z] = lim, 1;     else          return 0;}void dfs(int dep, int x, int y, int z){     if (a[x][y] == '$') printf("%d\n", lim), exit(0);     if (b[x][y] || dep + getdist(x, y) > lim) return;     for (int i = 0; i <= 4; ++ i)          if (~ c[x + dx[i]][y + dy[i]])               z |= 1 << c[x + dx[i]][y + dy[i]];     for (int i = 1; i <= 4; ++ i)     {          int xx = x + dx[i], yy = y + dy[i];          if (~ d[xx][yy] && (((z >> d[xx][yy]) & 1) || ((i == 1 || i == 3) ^ (e[xx][yy]))))               if (okay(dep, xx + dx[i], yy + dy[i], z))                    dfs(dep + 1, xx + dx[i], yy + dy[i], z);          if (! b[xx][yy])               if (okay(dep, xx, yy, z))                    dfs(dep + 1, xx, yy, z);     }}void work(){     for (lim = 1; lim <= 10000; ++ lim)          dfs(0, x1, y1, 0);     puts("10001");}void init(){     scanf("%d%d\n", & n, & m);     for (int i = 1; i <= n; ++ i) gets(a[i] + 1);     for (int i = 0; i <= n + 1; ++ i) a[i][0] = a[i][m + 1] = '*', b[i][0] = b[i][m + 1] = 1;     for (int j = 0; j <= m + 1; ++ j) a[0][j] = a[n + 1][j] = '*', b[0][j] = b[n + 1][j] = 1;     memset(c, 0xFF, sizeof c), memset(d, 0xFF, sizeof d);     for (int i = 1; i <= n; ++ i)          for (int j = 1; j <= m; ++ j)          {               if (a[i][j] == '#') x1 = i, y1 = j;               if (a[i][j] == '$') x2 = i, y2 = j;               if (a[i][j] == '*' || 'A' <= a[i][j] && a[i][j] <= 'z') b[i][j] = 1;               if ('1' <= a[i][j] && a[i][j] <= '9') c[i][j] = a[i][j] - '1';               if ('A' <= a[i][j] && a[i][j] <= 'Z') d[i][j] = a[i][j] - 'A', e[i][j] = 0;               if ('a' <= a[i][j] && a[i][j] <= 'z') d[i][j] = a[i][j] - 'a', e[i][j] = 1;          }}int main(){     freopen("palamaze.in", "r", stdin);     freopen("palamaze.out", "w", stdout);          init();     work();          return 0;}