經典算法(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;
            }
        }
    }

代碼執行結果:

在這裏插入圖片描述

:“你看,尋找通路的時候制定的策略不一樣,最後走的路也不一樣。這兒涉及到最短路徑的問題,等下一次給你再講


由於水平有限,本博客難免有不足,懇請各位大佬不吝賜教!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章