数据结构与算法之递归实战--走迷宫

数据结构与算法之递归基础

一、需求

经典的迷宫问题,就是:一颗小球通过移动格子,最终要走到目的地。移动格子到目的地的这段路径就是最终的结果。但是格子有障碍物,移动的过程中遇到障碍物的话是不能继续移动的,需要换其他格子去走。如下图:
在这里插入图片描述

二、coding

1、代码实现格子

思路:

首先这是一个8*7的网格,用1代表障碍物。从图中可以分析出
1.上下左右四面都是障碍物。也就是:第1行的第1-7列都是障碍物;第7行的第1-7列都是障碍物;第1列的第1-8行都是障碍物;第6列的第1-8行都是障碍物。
2.第四行的第一二两列是障碍物,也就是 map[3][1] = 1; map[3][2] = 1;

public class MiGong {
    public static void main(String[] args) {
        // 先创建一个二维数组,模拟迷宫
        // 地图  8行7列
        int[][] map = new int[8][7];
        // 使用1表示障碍物
        for (int i = 0; i < 7; i ++) {
            map[0][i] = 1;
            map[7][i] = 1;
        }
        for (int i = 0; i < 8; i++) {
            map[i][0] = 1;
            map[i][6] = 1;
        }

        // 第四行,第二三列有两个障碍物
        map[3][1] = 1;
        map[3][2] = 1;

        // 输出地图
        System.out.println("地图的情况:");
        for (int i = 0; i < 8; i ++) {
            for (int j = 0; j < 7; j++) {
                System.out.print(map[i][j] + " ");
            }
            System.out.println();
        }
    }
}

地图的情况:
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 1 1 1 1

2、思路分析

1、使用递归算法来给小球找路
2、定义二维数组,来画出墙和障碍物,障碍物用数字1表示
3、定义好起始位置也目的地。起始位置:【1, 1】目的地:【6,5】
4、定义数字0表示该点没走过,数字1表示障碍物;数字2表示该路可以走通;数字3表示已经走过该路,但是该点走不通
5、定义策略:先走下面,下面走不通再走右边,右边走不通就走上面,上面走不通就走左边。下->右->上->左的顺序。

3、思路图解

若按照下->右->上->左的顺序走,那最终应该是这样的结果
在这里插入图片描述

4、完整代码

public class MiGong {
    public static void main(String[] args) {
        // 先创建一个二维数组,模拟迷宫
        // 地图  8行7列
        int[][] map = new int[8][7];
        // 使用1表示障碍物
        for (int i = 0; i < 7; i ++) {
            map[0][i] = 1;
            map[7][i] = 1;
        }
        for (int i = 0; i < 8; i++) {
            map[i][0] = 1;
            map[i][6] = 1;
        }

        // 第四行,第二三列有两个遮挡物
        map[3][1] = 1;
        map[3][2] = 1;

        // 输出地图
        System.out.println("地图的情况:");
        for (int i = 0; i < 8; i ++) {
            for (int j = 0; j < 7; j++) {
                System.out.print(map[i][j] + " ");
            }
            System.out.println();
        }

        // 使用递归回溯给小球找路
        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] + " ");
            }
            System.out.println();
        }
    }

    /**
     * 使用递归回溯来给小球找路
     *
     * @param map 表示地图
     * @param i 从哪个位置开始找
     * @param j
     * @return 如果找到通路,就返回true,否则false
     */
    public static boolean setWay(int[][] map, int i, int j) {
        // 通路已经找到了
        if (map[6][5] == 2) {
            return true;
        } else {
            // 若当前这个点还没有走过
            if (map[i][j] == 0) {
                // 按照策略走:下->右->上->左
                // 假定这个点是可以走通的
                map[i][j] = 2;
                // 向下走
                if (setWay(map, i + 1, j)) {
                    return true;
                }
                // 向右走
                if (setWay(map, i, j + 1)) {
                    return true;
                }
                // 向上走
                if (setWay(map, i - 1, j)) {
                    return true;
                }
                // 向左走
                if (setWay(map, i, j - 1)) {
                    return true;
                }
                // 说明该点是走不通的,是死路一条
                map[i][j] = 3;
                return false;
            } else { // 如果map[i][j] != 0,那可能是1,2,3,那就没必要再走这条路了。即使是2也不要走了,因为2代表这条路已经走过了
                return false;
            }
        }
    }
}

地图的情况:
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 1 1 1 1
小球走过,并表识过的地图的情况
1 1 1 1 1 1 1
1 2 0 0 0 0 1
1 2 2 2 0 0 1
1 1 1 2 0 0 1
1 0 0 2 0 0 1
1 0 0 2 0 0 1
1 0 0 2 2 2 1
1 1 1 1 1 1 1

5、换个策略

上面案例是下->右->上->左的顺序。现在换成上->右->下->左的顺序来玩一把。正常的路径应该是如下:
在这里插入图片描述

package com.chentongwei.struct.recursion;

/**
 * Description:
 *
 * @author TongWei.Chen 2019-12-25 15:05:20
 */
public class MiGong {
    public static void main(String[] args) {
        // 先创建一个二维数组,模拟迷宫
        // 地图  8行7列
        int[][] map = new int[8][7];
        // 使用1表示障碍物
        for (int i = 0; i < 7; i ++) {
            map[0][i] = 1;
            map[7][i] = 1;
        }
        for (int i = 0; i < 8; i++) {
            map[i][0] = 1;
            map[i][6] = 1;
        }

        // 第四行,第二三列有两个遮挡物
        map[3][1] = 1;
        map[3][2] = 1;

        // 输出地图
        System.out.println("地图的情况:");
        for (int i = 0; i < 8; i ++) {
            for (int j = 0; j < 7; j++) {
                System.out.print(map[i][j] + " ");
            }
            System.out.println();
        }

        // 使用递归回溯给小球找路
        setWay2(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] + " ");
            }
            System.out.println();
        }
    }

    /**
     * 修改找路的策略,改成 上->右->下->左
     *
     * @param map:地图
     * @param i:从i、j出发开始找
     * @param j
     * @return
     */
    public static boolean setWay2(int[][] map, int i, int j) {
        // 通路已经找到了
        if (map[6][5] == 2) {
            return true;
        } else {
            // 若当前这个点还没有走过
            if (map[i][j] == 0) {
                // 按照策略走:上->右->下->左
                // 假定这个点是可以走通的
                map[i][j] = 2;
                // 向上走
                if (setWay2(map, i - 1, j)) {
                    return true;
                }
                // 向右走
                if (setWay2(map, i, j + 1)) {
                    return true;
                }
                // 向下走
                if (setWay2(map, i + 1, j)) {
                    return true;
                }
                // 向左走
                if (setWay2(map, i, j - 1)) {
                    return true;
                }
                // 说明该点是走不通的,是死路一条
                map[i][j] = 3;
                return false;
            } else { // 如果map[i][j] != 0,那可能是1,2,3,那就没必要再走这条路了。即使是2也不要走了,因为2代表这条路已经走过了
                return false;
            }
        }
    }
}

地图的情况:
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 1 1 1 1
小球走过,并表识过的地图的情况
1 1 1 1 1 1 1
1 2 2 2 2 2 1
1 0 0 0 0 2 1
1 1 1 0 0 2 1
1 0 0 0 0 2 1
1 0 0 0 0 2 1
1 0 0 0 0 2 1
1 1 1 1 1 1 1

三、扩展

上述的策略(走路顺序)可以自定义,随意就好。如何找到最短路径的问题可以简单粗暴lowb的方法就是:
将所有的策略都走一遍,然后存到数组里,最后遍历数组中2(走通的代表)数量最少的那条路径。

发布了28 篇原创文章 · 获赞 33 · 访问量 8298

猜你喜欢

转载自blog.csdn.net/ctwctw/article/details/103717863