经典算法(20)给女朋友讲明白 迷宫问题

写在前面: 我是 「扬帆向海」,这个昵称来源于我的名字以及女朋友的名字。我热爱技术、热爱开源、热爱编程。技术是开源的、知识是共享的

这博客是对自己学习的一点点总结及记录,如果您对 Java算法 感兴趣,可以关注我的动态,我们一起学习。

用知识改变命运,让我们的家人过上更好的生活

相关文章

点此查看 【算法系列】 博客文章


1、问题描述

今天女朋友在刷算法题,委屈巴巴的问我迷宫问题如何解决

在这里插入图片描述
先看一下问题的描述

有一个迷宫地图,其中设置了障碍物,四周还有墙壁。只能横着走或竖着走,不能斜着走。从一个位置走到下一个位置只能通过向上(或者向右、或者向下、或者向左)的策略来实现。一个人从起点出发,如何找到一条到达终点的通路?

看完问题描述,我就大概画了一个迷宫图,如下图所示:

迷宫图示
在这里插入图片描述

2、实现逻辑

我让她看这个图,然后思考如何实现?

:“用二维数组?”

:“对的!在这个算法中,使用二维矩阵来模拟迷宫地图”

:“迷宫中的通路和墙壁如何表示?”

:“可以使用0和1表示”

:“对,很聪明!1 代表该位置不能到达(如墙壁或者遮挡物),0 代表该位置可以到达。”

:“比如小明在迷宫中寻找通路的时候,有没有重复走的情况。如果重复走,如何避免这个情况?”

:“每当走过一个位置就将迷宫地图的对应位置做一个标记,以免重复走,一步步的寻找通路最终到达终点位置。”

到这里,看来她也明白了好多!很开心

在这里插入图片描述
:“从每一个位置出发,在走下一步的时候都可以有几种选择?”

:“从每一个位置出发,在走下一步的时候都有四种选择(向上走、向右走、向下走、向左走)。”

然后我就分析了如何走的算法逻辑

  • 先选择一个方向开始走,如果该方向能够走下去,那么就往这个方向开始走,当前位置切换为下一个位置。
  • 如果这个方向不能走,那么换个方向开始走。
  • 如果所有方向都走不通,那么退出当前位置,到上一步的位置去,当前位置切换为上一步的位置。
  • 一直这样执行下去,如果当前位置是终点,那么结束。如果走过了所有的路径都没能到达终点,那么说明这个迷宫走不出来。

:“现在明白没?”

:“明白了!”

:“那你想想如何实现这个算法?”

:使用 递归的方式求解

:“还有其它方式没? 广度优先遍历深度优先遍历 会不会?”

她:“不会!”

:“嗯嗯,那你就用递归的方式实现吧!首先制定 在迷宫中寻找出路的策略依次是:向上走、向右走、向下走、向左走


接下来就开始写代码吧

3、代码实现

:“你先用二维矩阵画出迷宫地图,包括挡板的位置”

她噼里啪啦一顿操作就写完了

public class Maze {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        int i; // 横坐标
        int j; // 纵坐标

        // 创建一个10×10的地图
        int[][] map = new int[10][10];

        // 设置左、右两边为墙,用“1”来代替墙面
        for (i = 0; i < 10; i++) {
            map[i][0] = 1;
            map[i][9] = 1;
        }

        // 设置上、下两边为墙,用“1”来代替墙面
        for (i = 0; i < 10; i++) {
            map[0][i] = 1;
            map[9][i] = 1;
        }

        // 设置挡板位置
        map[4][1] = 1;
        map[4][2] = 1;
        map[4][3] = 1;

        System.out.println("迷宫地图的情况:");
        for (i = 0; i < 10; i++) {
            for (j = 0; j < 10; j++) {
                System.out.print(map[i][j] + " ");
            }
            System.out.println();
        }
    }
}

迷宫地图的情况:
在这里插入图片描述


:“现在你可以写个方法,在迷宫地图中寻找通路”

她噼里啪啦一顿操作就写完了,代码如下:

public class Maze {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        int i; // 横坐标
        int j; // 纵坐标

        // 创建一个10×10的迷宫地图
        int[][] map = new int[10][10];

        // 设置迷宫地图的左、右两边为墙,用“1”来代替墙面
        for (i = 0; i < 10; i++) {
            map[i][0] = 1;
            map[i][9] = 1;
        }

        // 设置迷宫地图的上、下两边为墙,用“1”来代替墙面
        for (i = 0; i < 10; i++) {
            map[0][i] = 1;
            map[9][i] = 1;
        }

        // 设置迷宫地图中的挡板位置
        map[4][1] = 1;
        map[4][2] = 1;
        map[4][3] = 1;

        System.out.println("迷宫地图的情况:");
        for (i = 0; i < 10; i++) {
            for (j = 0; j < 10; j++) {
                System.out.print(map[i][j] + " ");
            }
            System.out.println();
        }

        System.out.println("输入小明的起始点 m:");
        int m = scanner.nextInt();

        System.out.println("输入小明的起始点 n:");
        int n = scanner.nextInt();

        // 寻找迷宫的出路
        mazeTrack(map, m, n);

        System.out.println("小明走过,并标识的迷宫地图的情况:");
        for (i = 0; i < 10; i++) {
            for (j = 0; j < 10; j++) {
                System.out.print(map[i][j] + " ");
            }
            System.out.println();
        }
    }

    /**
     * @param maze 表示迷宫地图
     * @param i   小明从哪个位置开始找
     * @param j   小明从哪个位置开始找
     * @return 如果小明找到了通路,就返回true
     */
    public static boolean mazeTrack(int[][] maze, int i, int j) {
        if (maze[8][8] == 2) { // 如果迷宫中的(8,8)这个点标记为“2”,则说明小明已经找到了出口
            return true;
        } else {
            if (maze[i][j] == 0) { // 当前这个点还没走过
                maze[i][j] = 2;
                if (mazeTrack(maze, i - 1, j)) { // 探索向上走是否可行
                    return true;
                } else if (mazeTrack(maze, i, j + 1)) { // 探索向右走是否可行
                    return true;
                } else if (mazeTrack(maze, i + 1, j)) { // 探索向下走是否可行
                    return true;
                } else if (mazeTrack(maze, i, j - 1)) { // 探索向左走是否可行
                    return true;
                } else {
                    // 如果在探索过程中该点走不通,则标记为“3”
                    maze[i][j] = 3;
                    return false;
                }

            } else {
                return false;
            }
        }
    }
}

代码执行结果:
在这里插入图片描述

看着运行结果,她满脸微笑,看着很开心的样子!O(∩_∩)O哈哈~

在这里插入图片描述

:如果改变寻找路的策略,如果在走下一步的时候 按向下、向右、向上、向左这样走,结果会是啥样的。

:那我修改一下代码

public static boolean mazeTrack(int[][] maze, int i, int j) {
        if (maze[8][8] == 2) { // 通路已经找到
            return true;
        } else {
            if (maze[i][j] == 0) { // 当前这个点还没走过
                maze[i][j] = 2;
                if (mazeTrack(maze, i + 1, j)) { // 探索向下走是否可行
                    return true;
                } else if (mazeTrack(maze, i, j + 1)) { // 探索向右走是否可行
                    return true;
                } else if (mazeTrack(maze, i - 1, j)) { // 探索向上走是否可行
                    return true;
                } else if (mazeTrack(maze, i, j - 1)) { // 探索向左走是否可行
                    return true;
                } else {
                    // 该点走不通,标记为“3”
                    maze[i][j] = 3;
                    return false;
                }

            } else {
                return false;
            }
        }
    }

代码执行结果:

在这里插入图片描述

:“你看,寻找通路的时候制定的策略不一样,最后走的路也不一样。这儿涉及到最短路径的问题,等下一次给你再讲


由于水平有限,本博客难免有不足,恳请各位大佬不吝赐教!

  • 59
    点赞
  • 105
    收藏
    觉得还不错? 一键收藏
  • 61
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 61
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值