【小白学算法】bfs超详细解析+例题[kuangbin]简单搜索-三维地宫
题面
你被困在一个3D地牢中,需要找到最快的逃离方式!地牢由单位立方体组成,这些立方体可能填满了岩石,也可能没有填满。向北、南、东、西、上或下移动一个单位需要一分钟的时间。你不能对角线移动,迷宫的四周被坚实的岩石包围着。
是否可能逃脱?如果是,需要多长时间?
输入
输入包括多个地牢。每个地牢描述以包含三个整数 L、R 和 C(均限制为 30 大小)的一行开始。
L 是构成地牢的层数。
R 和 C 是构成每个层面平面的行数和列数。
然后将跟随 L 个块,每个块包含 R 行,每行包含 C 个字符。每个字符描述地牢的一个单元格。一个充满岩石的单元格用 '#' 表示,空单元格用 '.' 表示。你的起始位置由 'S' 表示,出口由字母 'E' 表示。每个层面后都有一个空行。输入以 L、R 和 C 三个零终止。
输出
每个迷宫生成一行输出。如果可以到达出口,打印形式如下的一行:
Escaped in x minute(s).
其中 x 被替换为逃脱所需的最短时间。
如果无法逃脱,打印以下行:
Trapped!
样例
| Input | Output |
|---|---|
|
3 4 5 S.... .###. .##.. ###.# ##### ##### ##.## ##... ##### ##### #.### ####E 1 3 3 S## #E# ### 0 0 0 |
Escaped in 11 minute(s). Trapped! |
题目分析
这是一道经典的三维bfs最短路径问题,由题面可知 你被困在一个3D立方体地牢中(L为层数,每层有R行C列)每个位置是一个单位立方体:
-
`'#'` 表示岩石,不能走 -
`'.'` 表示空地,可以走 -
`'S'` 表示起点 -
`'E'` 表示出口移动规则:
-
只能向,前、后、左、右、上、下六个方向走 -
一步为一分钟 -
不能斜着走,即只能走六个方位的正方向要求:
-
如果能找到出口,按要求输出最短时间 -
不能则输出“Trapped!”
解题思路
首先,在输入地图时找到入口位置S(即你的bfs的起点)以及出口位置E(你的bfs的终点),并记录坐标,由于我们需要找到出口,其实本质就是找到最短路径(dfs也可以实现,但是dfs“一条路走到黑”且不一定找到出口的情况在时间复杂度上效率太低,而bfs只需将所有格子访问一次就可以判断能否逃脱并的出最短路径),所以根据广度优先原则,首先入口入队列,作为起点,其次遍历每个位置的六个方向,判断是否可走,可走的方位坐标入队列,然后一次取出队顶的坐标继续判断,直至找到出口位置,由于我们是广度优先,所以只要能到达出口位置,此时的路径一定是最短路径,当所有位置都访问完后依然没有找到出口,则说明本图没有路径可从入口到达出口,即被困。
本题的“坑”
-
L,R,C不超过30,可以用char str[31][31][31]来存图,每个单元格单独读取即可,(不能用string直接读整行,应为输入时没层之间有空行)
-
防止重复走,所以我们每次入队列一个坐标后就把该点标记为"#",表示不可走。
-
在判断是否可走的时候不能只判断“ . ”,还要判断"E",即只要不为"#"就可以走。
完整题解
#include<iostream>
#include<cstring>
#include<iomanip>
#include<queue>
using namespace std;
int n;
int l,r,c;
int m, arr[11]; // arr 用于记录方案
bool vis[10][10];
//int ans=0;
int orx,ory,orz;
int ulx,uly,ulz;
char str[31][31][31];
struct root{
int x;
int y;
int z;
int depth;
}poi;
int dx[6]={-1,1,0,0,0,0};
int dy[6]={0,0,-1,1,0,0};
int dz[6]={0,0,0,0,-1,1};//六个方向坐标的变化
int bfs(){
queue<root> q;
root point;
point.x=orx;
point.y=ory;
point.z=orz;
point.depth=0;
q.push(point);//入口点入队列,作为bfs的起点
while(!q.empty()){//队列为空只有一种情况,所有点全判断完
root p,t=q.front();
q.pop();
if(t.x==ulx&&t.y==uly&&t.z==ulz){
return t.depth;
}
for(int i=0;i<6;i++){
int nx=t.x+dx[i],ny=t.y+dy[i],nz=t.z+dz[i];//每个点判断六个方向的单元格
if(nx>=0&&nx<l&&ny>=0&&ny<r&&nz>=0&&nz<c&&str[nx][ny][nz]!='#'){//边界检查,保证坐标是合法的
str[nx][ny][nz]='#';//标记访问过
p.depth=t.depth+1;//访问该位置,步数(即bfs深度)加1
p.x=nx;
p.y=ny;
p.z=nz;
q.push(p);//可行位置入队
}
}
}//所有点全判断完后依然没有路径可达,则返回0,说明不可达
return 0;
}
int main(){
while(cin>>l>>r>>c&&l!=0&&r!=0&&c!=0){
// ans=0;
for(int i=0;i<l;i++){
for(int j=0;j<r;j++){
for(int k=0;k<c;k++)
{
cin>>str[i][j][k];
if(str[i][j][k]=='S') {
orx = i, ory = j, orz = k;//记录入口坐标
}else if(str[i][j][k]=='E'){
ulx=i,uly=j,ulz=k;//记录出口坐标
}
}
}
}
int ans=bfs();//记录图的“最短路径”
if(ans){//若有值则可以逃脱,否则无法逃脱
cout<<"Escaped in "<<ans<<" minute(s)."<<endl;
}else{
cout<<"Trapped!"<<endl;
}
}
return 0;
}

浙公网安备 33010602011771号