题目
题目传送门
You are trapped in a 3D dungeon and need to find the quickest way out! The dungeon is composed of unit cubes which may or may not be filled with rock. It takes one minute to move one unit north, south, east, west, up or down. You cannot move diagonally and the maze is surrounded by solid rock on all sides.
Is an escape possible? If yes, how long will it take?
你在一个立体的迷宫里,现在问你,走出该立体迷宫的最短路径是多少?或者说,走不出来,就输出一个被困住的语句
Input
The input consists of a number of dungeons. Each dungeon description starts with a line containing three integers L, R and C (all limited to 30 in size).
L is the number of levels making up the dungeon.
R and C are the number of rows and columns making up the plan of each level.
Then there will follow L blocks of R lines each containing C characters. Each character describes one cell of the dungeon. A cell full of rock is indicated by a ‘#’ and empty cells are represented by a ‘.’. Your starting position is indicated by ‘S’ and the exit by the letter ‘E’. There’s a single blank line after each level. Input is terminated by three zeroes for L, R and C.
翻译:从’S’的位置开始,位置为’.‘的可以走,位置为’#'的不可以走,从’S’走到位置为’E’的地方。因为是立体的,所以有六个方向。往东南西北和上下,每走一个位置,需要1分钟。问你走到最后,所需要的最短时间是多少?
或者是走不到,就输出被困在迷宫中!
Output
Each maze generates one line of output. If it is possible to reach the exit, print a line of the form
Escaped in x minute(s).
where x is replaced by the shortest time it takes to escape.
If it is not possible to escape, print the line
Trapped!
翻译:能走到,就输出最小步数,走不到,就输出被困住!
思路
因为是立体的迷宫,而且本来只会深搜,不想那么快就学多种搜索,本来还想深搜来一波,结果发现,如果用深搜,那是绝对顶不住的,太容易爆了,所以,只能去学了广搜!
跟深搜有点相似,需要开一个标记数组,而且,所有的全局变量在每一次重新输入后,都要进行一遍初始化!
我们先将起点’S’加入到队列中,然后,往起点的东西南北上下六个方向搜索可以走的节点,并且步数加1.然后,把可扩展的节点加到队列里面,搜索完成之后,将队首弹出,直到队列为空,一旦到达终点,把找到路径的标记flag标记为找到了,方便输出的判断;然后,要判断当前的步数是不是小于最小值,如果是的话,那么就改变最小值,否则的话,继续搜索直到队列为空!
代码
import java.util.Scanner;
import java.util.LinkedList;
import java.util.Queue;
class Point{
int z; //层数
int x; //行坐标
int y; //列坐标
int step;//步数
}
public class Main{
static int a;//层数
static int b;//行数
static int c;//列数
static char map[][][]=new char [35][35][35];//地图,最高的限制是30
static boolean visited[][][]=new boolean[35][35][35];//标记数组,标记是否访问了
//六个方向的数组,东北西南上下
static int direction_z[]={0,0,0,0,-1,1};
static int direction_x[]={1,0,-1,0,0,0};
static int direction_y[]={0,-1,0,1,0,0};
static Queue<Point> queue =new LinkedList();//节点队列
static int min=Integer.MAX_VALUE;//最短路径
static int flag=0;//标记是否找到了路径
public static void main(String args[]){
Scanner reader=new Scanner(System.in);
while (reader.hasNextInt())
{
a=reader.nextInt();//层数
b=reader.nextInt();//每一层的行数
c=reader.nextInt();//每一层的列数
flag=0;//没有找到路径
min=Integer.MAX_VALUE;//初始化最小值
queue.clear();
String test=reader.nextLine();//接收上面三个数的输入到最后的回车
if (a==0 && b==0 &&c==0)
break;
//先初始化整个标记数组
for (int k=0;k<a;++k)
for(int i=0;i<b;++i)
for(int j=0;j<c;++j)
visited[k][i][j]=false;
for (int k=0;k<a;++k)
{
if (k>=1)
test=reader.nextLine();//每次输入一层后的换行符
for (int i=0;i<b;++i)
{
String d=reader.nextLine();
for(int j=0;j<c;++j)
map[k][i][j]=d.charAt(j);
}
}
//找到迷宫出发点,开始进行搜索
for(int k=0;k<a;++k)
for(int i=0;i<b;++i)
for(int j=0;j<c;++j)
if(map[k][i][j]=='S')
{
Point start=new Point();
start.z=k;
start.x=i;
start.y=j;
queue.offer(start); //将起点入队,开始广搜
visited[k][i][j]=true;//已经走过
}
//搜到队列为空
while(!queue.isEmpty())
{
int now_z=queue.peek().z;
int now_x=queue.peek().x;
int now_y=queue.peek().y;
int step=queue.peek().step;
if(map[now_z][now_x][now_y]=='E')
{
++flag;//表示找到了终点
if(step<min) //看看当前步数是不是小于最小步数
{
min=step;
}
}
for(int g=0;g<=5;++g)
{
int tz=now_z+direction_z[g];
int tx=now_x+direction_x[g];
int ty=now_y+direction_y[g];
if(check(tz,tx,ty))
{
Point temp=new Point();
temp.z=tz;
temp.x=tx;
temp.y=ty;
temp.step=step+1;
queue.offer(temp);
visited[tz][tx][ty]=true;//设置为已访问
}
}
queue.poll();//将队首元素出队
}
if (flag>0) //找到了出口
System.out.println("Escaped in "+min+" minute(s).");
else
System.out.println("Trapped!"); //困在地牢
}
}
public static boolean check(int o,int p,int q)
{
return o>=0 && o<a && p>=0 && p<b && q>=0 && q<c && (map[o][p][q]=='.' || map[o][p][q]=='E') && visited[o][p][q]==false;
}
}
结果
AC了,这种感觉还挺好的,毕竟,在学习深搜的时候,备受挫折,不过也许是有了深搜的铺垫,这一道题就直接AC了,还是很有收获的.
对于这种比较老的oj,新建队列的时候,要把后面的类型给直接去掉就可以,不然会一直报一个错误,导致今晚wa了好几次,最后在大佬的指点下,才发现要这样子修改。
static Queue<Point> queue =new <Point> LinkedList();//节点队列,上面这种,在自己的电脑上跑得起来,但是到了oj上面就会报错,以后切记
static Queue<Point> queue =new LinkedList();//节点队列
颇有收获,其实深搜和广搜有点类似,就是深搜需要回溯,所耗费的时间多而且可能爆栈,相比较与深搜,广搜一个节点就直接访问一次,速率提高了不少,不过也不是所有题目都可以用广搜来解决,有一些用深搜才能解决【八皇后问题。。。】
各有特点,算法之路无穷尽也,漫漫长夜,坚持修行!