寫在前面: 我是 揚帆向海,這個暱稱來源於我的名字以及女朋友的名字。我熱愛技術、熱愛開源、熱愛編程。
技術是開源的、知識是共享的
。
這博客是對自己學習的一點點總結及記錄,如果您對 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;
}
}
}
代碼執行結果:
我:“你看,尋找通路的時候制定的策略不一樣,最後走的路也不一樣。這兒涉及到最短路徑的問題,等下一次給你再講
”
由於水平有限,本博客難免有不足,懇請各位大佬不吝賜教!