迷宫描述:一个网格迷宫由n行m列的单元格组成,每个单元格要是空地(用0表示),或者是障碍物(用1表示)。寻找一条从起点到终点的移动序列,只能上下左右移动到相邻单元格。任何时候都不能在有障碍物的单元格中,也不能走到迷宫之外。起点为左上角和终点右下角。
问题:解决迷宫路径查找问题,寻找一条从左上角迷宫入口到右下角迷宫出口的一条有效路径,0代表可走,1代表不能行走,找到请输出最终的迷宫和路径信息,找不到请输出不存在有效路径。
迷宫示例
0 1 1 1 1
0 1 1 1 1
0 0 0 0 1
1 1 1 0 1
1 1 1 0 0
问题分析:
迷宫可以用二维数组表示,迷宫的起点和终点已经确定,为左上角到右下角。现在需要设计一个程序,可以让它自动从左上角走到右下角,如果走进死路了,可以退回去,换一条路走。需要解决的问题有:
- 如何确定哪个方向可以走,如果有多个方向可以走,怎么确定走哪个?
- 如何让程序一直走下去?进入死路了如何退出来?
- 如何让程序停下来?
显然可走的方向有四个,上下左右。走的顺序可以提前设定,比如顺序为:→ ↓ ← ↑。什么方向不能走?节点为1的,和来的方向的节点。
可以用栈来存储当前走过的节点,如果这个节点四个方向都不能走,则将栈顶节点出栈,回退到上一个位置。
如何让程序一直走下去?这里需要一个循环结构,首先想到的就是while循环,现在需要设计的是内部的处理过程和循环条件。
现在已经有了一个大致的思路,还未解决的问题有:
- 如何让节点不会回到来的位置。
- 如何让节点不会又走进之前走过的死路。
判断节点可以走的条件是该位置为0,所以可以把节点走过的位置的值改为2,走入死路后,回退时可以将该位置改为1,这样就不会再次走进这条路。
现在基本解决了大多数的问题,可以开始写了。
首先需要一个节点类,它要存储当前节点的位置。
public class Point {
public int[] pointArray;//存储当前位置坐标
public Point(int x,int y){
pointArray=new int[2];
pointArray[0]=x;
pointArray[1]=y;
}
}
一个节点操作类
public class Labyrinth {
Scanner scanner=new Scanner(System.in);
Stack<Point> stack=new Stack<>();
int[][] arr;
public Labyrinth(){
}
public int[][] inputNum(){
System.out.println("请输入迷宫行列数:");
int line = scanner.nextInt();//行
int row = scanner.nextInt();//列
System.out.println("请输入迷宫:");
int[][] arr=new int[line][row];
for(int i=0;i<line;i++){
for(int k=0;k<row;k++){
arr[i][k]=scanner.nextInt();
}
}
return arr;
}
public void show(){
for(int i=0;i<arr.length;i++){
System.out.println(Arrays.toString(arr[i]));
}
}
public void findPath(){//核心方法
int line=arr.length;
int row=arr[0].length;
boolean flag=true;
Point point=new Point(0,0);
stack.push(point);
boolean anser=true;
while (flag){
if(stack.empty()){
anser=false;
break;
}
Point point1=stack.peek();
int x=point1.pointArray[0];
int y=point1.pointArray[1];
if(x==line-1&&y==row-1&&arr[line-1][row-1]==0){
arr[line-1][row-1]=2;
break;
}
int index=canRun(x,y);
operation(index,x,y);
}
}
//找到可以走的方向后,对该方向的节点做入栈操作,若该节点四个方向都走不了,则出栈该节点
public void operation(int index,int x,int y){
switch (index){
case 1:
Point point1=new Point(x,y+1);
stack.push(point1);
arr[x][y]=2;
break;
case 2:
Point point2=new Point(x+1,y);
stack.push(point2);
arr[x][y]=2;
break;
case 3:
Point point3=new Point(x,y-1);
stack.push(point3);
arr[x][y]=2;
break;
case 4:
Point point4=new Point(x-1,y);
stack.push(point4);
arr[x][y]=2;
break;
case 5://四个方向都走不了
arr[x][y]=1;
stack.pop();
break;
}
}
//判断哪个方向可以走
public int canRun(int x,int y){
if(y+1<arr[0].length&&arr[x][y+1]==0){
return 1;
}
if(x+1<arr.length&&arr[x+1][y]==0){
return 2;
}
if(y-1>=0&&arr[x][y-1]==0){
return 3;
}
if(x-1>=0&&arr[x-1][y]==0){
return 4;
}
return 5;//四个方向都走不了
}
public static void main(String[] args) {
Labyrinth labyrinth=new Labyrinth();
labyrinth.arr=labyrinth.inputNum();
labyrinth.findPath();
labyrinth.show();
}
}
测试:
结果:
该方法缺点:只能找到一条路径,后续会更新优化后的方法