迷宫问题(Java实现,求最短路径)

题目链接

迷宫问题

定义一个二维数组: int maze[n][m]; 它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

  • 输入描述:

一个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,
};
  • 样式输出:

(0,0)
(1,0)
(2,0)
(2,1)
(2,2)
(2,3)
(2,4)
(3,4)
(4,4)

Java迷宫问题基本思路

原题中给的测试用例不适合举例,我决定重新给一个测试用例。

int maze[6][7] = {
0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 0,
0, 1, 0, 0, 0, 1, 0,
0, 1, 0, 1, 0, 0, 0,
0, 1, 0, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0,
};

根据观察,我们可得找到两条路径。显然,走蓝色这条的路径是最短的。
在这里插入图片描述
根据以上例子,我们得到了大概的思路

  1. 使用深度优先搜索找到能够到达终点的路径
  2. 利用二维顺序表(ArrayList<ArrayList<Integer>>保存每一条能够到达终点的路径
  3. 找到其中最短的路径输出即可。

在使用 深度优先搜索的过程中,要注意一下几点:

  • 为了防止死循环,我们需要将走过的路置为 2
  • 我们事先并不知道能够通过的路径有多少条,所以走完之后存在 回溯 的过程,也就是把之前之前走过的路还原为 0 且 之前的结果 remove();

代码实现

	static ArrayList<ArrayList<Integer>> res = new ArrayList<>();
    public static void main(String[] args) {
        //利用 Scanner 读入数据
        Scanner sc = new Scanner(System.in);
        //拥有多组数据
        while (sc.hasNextInt()) {
            //读入列和行
            int n = sc.nextInt();
            int m = sc.nextInt();
            //读入数组
            int[][] maze = new int[n][m];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    maze[i][j] = sc.nextInt();
                }
            }
			
			// 第一步
            //创建一个 ArrayList<Integer> step 记录步数
            ArrayList<Integer> step = new ArrayList<>();
            //调用 dfs 函数
            dfs(maze,0,0,n,m,step);

			// 第三步
            //得到结果 筛选最短路径
            int size = Integer.MAX_VALUE;
            int index = 0;
            for (int i = 0; i < res.size(); i++) {
                if (res.get(i).size() < size) {
                    size = res.get(i).size();
                    index = i;
                }
            }
			
			//第三步
            //将最短路径保存并输出
            step = res.get(index);
            for (int i = 0; i < step.size(); i+=2) {
                System.out.println("(" + step.get(i) + "," + step.get(i+1) + ")");
            }

            // 清空 res 继续下一个迷宫
            // 这一步其实不仅仅是循环输入的时候用到
            //个人觉得清除后可以节省空间。
            res.clear();
        }
    }

    public static void dfs(int[][] maze,int i,int j,int n,int m,ArrayList<Integer> step) {
        // 越界 、 有墙 、 已经走过
        if (i < 0 || i >= n || j < 0 || j >= m || maze[i][j] == 1 || maze[i][j] == 2) {
            return;
        }

        //如果到达终点
        if (i == n - 1 && j == m - 1) {
            //添加终点坐标
            step.add(i);
            step.add(j);
            res.add(new ArrayList<>(step));
            //回溯
            step.remove(step.size() - 1);
            step.remove(step.size() - 1);
        }
        //没有到达终点
        else {
            //添加当前坐标
            step.add(i);
            step.add(j);
            //标记为已经走过
            maze[i][j] = 2;
            // 递归
            dfs(maze, i + 1, j, n, m, step);
            dfs(maze, i, j + 1, n, m, step);
            dfs(maze, i - 1, j, n, m, step);
            dfs(maze, i, j - 1, n, m, step);
            // 回溯
            maze[i][j] = 0;
            step.remove(step.size() - 1);
            step.remove(step.size() - 1);
        }
    }

大概图解一下 dfs 代码

在这里插入图片描述

从 i == 0 到 i == 4,并未出现越界、墙、已经走过的情况,step.add(i,0)
i == 5,  j == 0, 下一次递归 i == 5,存在越界,返回到上一步继续递归 dfs(maze, i, j + 1, n, m, step), step.add(5,0);
i == 5,  j == 1, 下一次递归调用dfs(maze, i + 1, j, n, m, step), i == 5, 存在越界,返回到上一步 j == 1, 继续递归dfs(maze, i, j + 1, n, m, step),step.add(5,1);
i == 5,  j == 2, 下一次递归调用dfs(maze, i + 1, j, n, m, step), i == 5, 存在越界,返回到上一步 j == 2, 继续递归dfs(maze, i, j + 1, n, m, step),step.add(5,2);
i == 5,  j == 3, 下一次递归调用dfs(maze, i + 1, j, n, m, step), i == 5, 存在越界,返回到上一步 j == 3, 继续递归dfs(maze, i, j + 1, n, m, step),step.add(5,3);
i == 5,  j == 4, 下一次递归调用dfs(maze, i + 1, j, n, m, step), i == 5, 存在越界,返回到上一步 j == 4, 继续递归dfs(maze, i, j + 1, n, m, step),step.add(5,4);
i == 5,  j == 5, 下一次递归调用dfs(maze, i + 1, j, n, m, step), i == 5, 存在越界,返回到上一步 j == 5, 继续递归dfs(maze, i, j + 1, n, m, step),step.add(5,5);
i == 5,  j == 6, 满足 i == n-1 && j == m-1, step.add(5,6), res.add(new ArrayList<Integer>(step))

回溯
在这里插入图片描述

递归过程很多,不详细解释。

  • 18
    点赞
  • 96
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值