您的位置:首页 > 其它

【BFS】皇宫VS迷宫

2017-08-04 21:23 176 查看
问题描述

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

这道题一开始想的很复杂,以为很难但又能上手,考试的时候就尝试BFS了一下,有很多细节没考虑到,但还是得了最高分50.

考完到网上搜了下题解,结果很多博客都是说"这道题还是用来养眼算了。暴力搜索(不论是A*还是BFS)能得40分的样子。正解再说吧"

我也是服了。

有一个博客有正解,用的是迭代加深+A*,反正我是看不懂,所以只能靠自己了。

经过一次又一次的测试,终于AC了


看代码里的注释,上代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#define Open(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
#define Close fclose(stdin);fclose(stdout);
using namespace std;
char s[22][22],w;
struct xx{
int x,y,t,num,p[10]; //x,y坐标,t走到这里的步数,num当前钥匙数,p[i]=1表示有第i个钥匙
};
queue <xx> a;
int n,m,qx,qy,zx,zy,l[]={-1,1,0,0},r[]={0,0,-1,1}; //4个方向
bool f[22][22][11];
int main(){
Open("palamaze");
ios::sync_with_stdio(false); //给cin提速的,用了后和scanf一样快,但此时cout无效
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
cin>>s[i][j];
if(s[i][j]=='#') qx=i,qy=j,s[i][j]='+'; //把起点置为可以走的
if(s[i][j]=='$') zx=i,zy=j;
}
a.push((xx){qx,qy,0,0,{0}});
while(!a.empty()){
xx now=a.front();
if(now.t>=10000) break;
if(s[now.x][now.y]=='$'){printf("%d",now.t);exit(0);}
a.pop();
if(f[now.x][now.y][now.num]) continue; //f[x][y][k]表示坐标为x,y,有k个钥匙的状态有没有出现过
f[now.x][now.y][now.num]=1;
for(int i=0;i<4;i++){ //先扫一遍看看有没有钥匙可以捡
w=s[now.x+l[i]][now.y+r[i]];
if(w>='1'&&w<='9') {
if(!now.p[w-'1']){
now.p[w-'1']=1;
now.num++;
}
}
}
for(int i=0;i<4;i++){ //向四个方向拓展
w=s[now.x+l[i]][now.y+r[i]];
if(w=='$') {printf("%d",now.t+1);exit(0);}
if(w=='+'||w>='1'&&w<='9') a.push((xx){now.x+l[i],now.y+r[i],now.t+1,now.num,{now.p[0],now.p[1],now.p[2],now.p[3],now.p[4],now.p[5],now.p[6],now.p[7],now.p[8],now.p[9]}});
if(w>='a'&&w<='z') { //如果是竖向管道
if(now.p[w-'a']) //如果有钥匙,那么横向也能走过去
if(r[i]&&s[now.x][now.y+r[i]*2]!='*')
a.push((xx){now.x,now.y+r[i]*2,now.t+1,now.num,{now.p[0],now.p[1],now.p[2],now.p[3],now.p[4],now.p[5],now.p[6],now.p[7],now.p[8],now.p[9]}});
if(l[i]&&s[now.x+l[i]*2][now.y]!='*')
a.push((xx){now.x+l[i]*2,now.y,now.t+1,now.num,{now.p[0],now.p[1],now.p[2],now.p[3],now.p[4],now.p[5],now.p[6],now.p[7],now.p[8],now.p[9]}});
}
if(w>='A'&&w<='Z'){ //同理
if(now.p[w-'A'])
if(l[i]&&s[now.x+l[i]*2][now.y]!='*')
a.push((xx){now.x+l[i]*2,now.y,now.t+1,now.num,{now.p[0],now.p[1],now.p[2],now.p[3],now.p[4],now.p[5],now.p[6],now.p[7],now.p[8],now.p[9]}});
if(r[i]&&s[now.x][now.y+r[i]*2]!='*')
a.push((xx){now.x,now.y+r[i]*2,now.t+1,now.num,{now.p[0],now.p[1],now.p[2],now.p[3],now.p[4],now.p[5],now.p[6],now.p[7],now.p[8],now.p[9]}});
}
}
}
printf("%d",10001); //BFS无法找到解,输出10001
Close;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bfs