迷宫问题,借助栈和回溯的思想解决
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; } } }