栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

递归-迷宫

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

递归-迷宫

文章目录
    • 问题
    • 问题分析
    • 代码实现
    • 结束语

问题

在一个地图上,给你一个起点、一个终点、地图上有障碍物,让你制定一条走到终点的路线(不需要求最短路径)
如图:

“1”表示障碍物“0”表示可走的路(1,1)是起点(6,5)是终点
(外围的障碍物不算坐标,且数组下标从0开始)


问题分析

解决这个问题就是求出从入口到出口的路径,在求解时,通常用的是“穷举求解”的方法,即从入口出发,顺着某一个方向向前试探,若能走通,则继续往前走,否则沿着原路退回(回溯)换一个方向再继续试探,直到到达终点为止。

有点类似于 深度优先搜索(深度优先搜索求的是最短路径,也就是最优解,深度优先这个算法后续我会再总结)。

认真思考我们会发现,其实找路的方式都是一样的

  1. 首先看当前位置是否可走?如果不可走就原路返回、往回走
  2. 如果当前位置可走,则再走下一步,看当前位置的上、下、左、右的路是否可走(当然究竟是先走上?先走下?先走左?先走右? 这个选择的顺序是自己定的,这个决策会影响到你最终找的路线

这样一来,其实我们已经将从起点到终点这个大问题 拆分为了一个个从当前位置找下一步的小问题


代码实现

编码约定

  • 地图我用一个二维数组表示
  • 数字“1”表示墙,数字“0”表示路
  • (1,1)位置表示起点,(6,5)位置表示终点
  • 数字“2”的标记表示该点已走过,数字“3”的标记表示该点是死路、前面走不通
  • 终点(6,5)的值默认为0,如果走到该点了就将其赋值为数字“6”(听起来比较吉利)

上代码

    public static void main(String[] args) {
		//先创建一个二维数组,用于模拟迷宫
        int[][] map = new int[8][7];
        //使用1表示墙,上下全部为1
        for (int i = 0; i < 7; i++) {
            map[0][i] = 1;
            map[7][i] = 1;
        }
        //左右全部为1
        for (int i = 0; i < 8; i++) {
            map[i][0] = 1;
            map[i][6] = 1;
        }
        map[6][1] = 1;
        map[3][2] = 1;
        map[5][2] = 1;
        map[4][2] = 1;
        map[2][3] = 1;
		// map[1][3] = 1;

        //打印输出迷宫,也就是打印输出二维数组
        System.out.println("地图的情况:");
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 7; j++) {
                System.out.print(map[i][j] + "t");
            }
            System.out.println();
        }
        System.out.println("=========================================");
        //调用自定义的setWay方法找路
        setWay(map, 1, 1);
        System.out.println("探测过的地图:");

        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 7; j++) {
                System.out.print(map[i][j] + "t");
            }
            System.out.println();
        }
    }


    public static void setWay(int[][] map,int i,int j){
        if (i==6 && j==5)
        {
            //已经到达终点
            System.out.println("已经到达终点");
            map[i][j] = 6;
            return;     // 回溯
        }
        else
        {
            if (map[i][j] == 0){    // 如果当前位置为0,则表示当前位置可走。然后再按照策略走下一步,下右上左的方向走
                // 将当前位置赋值为2 标记该位置已走
                map[i][j] = 2;
                // 开始寻找走下一步
                if (map[i+1][j] == 0){          //表示向下走
                    System.out.println("向↓走");
                    setWay(map, i+1, j);
                    // 如果从setWay这个子栈帧 返回回来   有两种情况 1、前面的路已经走不通(不可走)才返回的 2、已经找到迷宫终点才返回的
                    System.out.println("从"+(i+1)+"行"+j+"列回溯回来了, ↑");
                    // 如果是因为终点找到才返回的 那么此刻我们需要继续回溯,直接return ; 否则我们就不return,而是选择走其他方向的路
                    if (map[6][5] == 6) return;
                }
                if (map[i][j+1] == 0){    //表示向右走
                    System.out.println("向→走");
                    setWay(map, i, j+1);
                    System.out.println("从"+i+"行"+(j+1)+"列回溯回来了, ←");
                    if (map[6][5] == 6) return;
                }
                if (map[i-1][j] == 0){    //表示向上走
                    System.out.println("向↑走");
                    setWay(map, i-1, j);
                    System.out.println("从"+(i-1)+"行"+j+"列回溯回来了, ↓");
                    if (map[6][5] == 6) return;
                }
                if (map[i][j-1] == 0){    //表示向左走
                    System.out.println("向←走");
                    setWay(map, i, j-1);
                    System.out.println("从"+i+"行"+(j-1)+"列回溯回来了, →");
                    if (map[6][5] == 6) return;
                }
                //按照下右上左的顺序走完都走不通,则标记当前点为3,是死路
                map[i][j] = 3;
                System.out.println("走不通"+i+"行"+j+"列");
                return;     // 回溯
            }
            else {
                //当前点如果不为0,还可能为1、或者2、或者3 都表示不可走
                return;     // 回溯
            }
        }
    }

简约版的setWay方法(还是上面的逻辑)

    public static void setWay1(int[][] map, int row, int col) {
        if (row==6 && col==5) { // 如果到达(6,5)也就说明 已经到达了终点 直接回溯
            map[row][col] = 6;  // 将其赋值为6 (这个6 只是一个特殊值 没有啥特殊含义)
            return;
        }else {
            if (map[row][col] == 0) {   // 如果该点为0 则表示可以走
                // 1、首先将该点 置为2 以此来表示该点已走过
                map[row][col] = 2;
                // 2、按计划找下一步 先往↓ 再往→ 后往↑ 最后往← 的顺序 走下一步
                if (map[row+1][col] == 0) { // 如果向 ↓ 可走
                    setWay1(map, row+1, col);   // 往这个方向往后走
                    
                    if (map[6][5] == 6) return;
                }
                if (map[row][col+1] == 0) { // 如果向 → 可走
                    setWay1(map, row, col+1);   // 往这个方向往后走
                    if (map[6][5] == 6) return;
                }
                if (map[row-1][col] == 0) { // 如果向 ↑ 可走
                    setWay1(map, row-1, col);   // 往这个方向往后走
                    if (map[6][5] == 6) return;
                }
                if (map[row][col-1] == 0) { // 如果向 ← 可走
                    setWay1(map, row, col-1);   // 往这个方向往后走
                    if (map[6][5] == 6) return;
                }
                // 3、如果四个方向都走不通 则表示该点是死路  将其赋值为 3 然后return 回溯
                map[row][col] = 3;
                return;
            }else {     // 如果不为0 则表示该点不可走 可能是 2、 3、 6 直接return 回溯
                return;
            }
        }
    }

结束语

算法这东西,不光要多看、多想最主要的是多练,自己手敲一遍才更有效。
如果这篇文章有帮助到你,点击赞呗(*^▽^*)!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/309361.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号