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

皇宫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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值