迷宫问题,借助栈和回溯的思想解决
m*n的迷宫,只有一条正确的路,0表示通行,1表示墙壁。所以每个点都有四个方向可以移动,也就是x轴可以向左右移动,y轴可以向上下移动。移动的时候只有是0才能继续向后寻找迷宫的出口。如果找错了,则不断调整方位。如果最终没有走到终点,则就会回溯,找相反的方向,最终会找到一条正确的路。
所以定义一个四个探索方向的数组非常重要。
/**
* 迷宫的方向
*/
private static final int[][] DIRECTIONS = new int[][] {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
数组的几个元素分别表示
1、x轴向左移动一个方向,y轴不动
2、x轴向右移动一个方向,y轴不动
3、y轴向上移动一个方向,x轴不动
4、y轴向下移动一个方向,x轴不动
具体代码实现如下:
import java.util.Scanner;
import java.util.Stack;
/**
* HJ43 迷宫问题
* 描述
* 定义一个二维数组 N*M ,如 5 × 5 数组下所示:
* int maze[5][5] = {
* 0, 1, 0, 0, 0,
* 0, 1, 1, 1, 0,
* 0, 0, 0, 0, 0,
* 0, 1, 1, 1, 0,
* 0, 0, 0, 1, 0,
* };
* 它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的路线。入口点为[0,0],既第一格是可以走的路。
* 本题含有多组数据。
* 输入描述:
* 输入两个整数,分别表示二维数组的行数,列数。再输入相应的数组,其中的1表示墙壁,0表示可以走的路。数据保证有唯一解,不考虑有多解的情况,即迷宫只有一条通道。
*
* 输出描述:
* 左上角到右下角的最短路径,格式如样例所示
* 示例1
* 输入:
* 5 5
* 0 1 0 0 0
* 0 1 1 1 0
* 0 0 0 0 0
* 0 1 1 1 0
* 0 0 0 1 0
* 复制
* 输出:
* (0,0)
* (1,0)
* (2,0)
* (2,1)
* (2,2)
* (2,3)
* (2,4)
* (3,4)
* (4,4)
*/
public class Main {
/**
* 迷宫的方向
*/
private static final int[][] DIRECTIONS = new int[][] {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNextInt()){
int m = in.nextInt();
int n = in.nextInt();
int[][] arr = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
arr[i][j] = in.nextInt();
}
}
// 走迷宫
Stack<Position> dfs = dfs(arr, m, n);
for (Position e : dfs) {
System.out.println("(" + e.x + "," + e.y + ")");
}
}
}
/**
* 走迷宫
* @param arr 迷宫数组
* @param m 迷宫行数
* @param n 迷宫列数
* @return 迷宫的路径
*/
private static Stack<Position> dfs(int[][] arr, int m, int n) {
Stack<Position> stack = new Stack<>();
// 定义起点为已经探索过的
arr[0][0] = -1;
// 设置起点,并将起点入栈
Position position = new Position(0, 0, -1);
stack.push(position);
// 遍历栈
while (!stack.isEmpty()){
// 位置出栈
Position p = stack.pop();
int x = p.x;
int y = p.y;
// 获取方向,并加1取尝试
int d = p.d + 1;
while (d < 4){
// 因为一个点,在迷宫的二维数组中只能向上下左右方向移动,但是可能会导致边界溢出,需要处理边界问题
// DIRECTIONS[d][0]表示x坐标需要移动的位置,负数表示向左,整数表示向右
// DIRECTIONS[d][1]表示y坐标需要移动的位置,负数表示向左,整数表示向右
int i = x + DIRECTIONS[d][0];
int j = y + DIRECTIONS[d][1];
// 越界,或者值为1(表示墙,不能通行),等都是不可操作的,继续调整探索的方向
if (i < 0 || i >= m || j < 0 || j >= n || arr[i][j] != 0){
// 探索方向变化, 继续尝试
d++;
continue;
}
// 如果走到这里,说明当前点的值为0,并且下标不越界。可以通行,则数据入栈
stack.push(new Position(x, y, d));
// 重新迭代x,y,d,为下次迭代做准备
x = i;
y = j;
d = 0;
// 标记当前位置已经被探索过了
arr[x][y] = -1;
// 当遍历到最后一个点时,说明找到了迷宫的出口, 结束循环
if (x == m - 1 && y == n - 1){
stack.push(new Position(x, y, d));
return stack;
}
}
}
return new Stack<>();
}
/**
* 位置
*/
public static class Position {
// 横坐标方向
int x;
// 众坐标方向
int y;
// 探索的方向
int d;
public Position(int x, int y,int d) {
this.d = d;
this.x = x;
this.y = y;
}
}
}



京公网安备 11010502036488号