1. 程式人生 > >迷宮(回溯演算法)

迷宮(回溯演算法)

要想解決迷宮問題,首先搞明白八皇后,迷宮問題是回溯和貪心的產物。
題目:現有一個迷宮如圖:
這裡寫圖片描述
黃色五角星為迷宮的起點,紅色五角星為迷宮的終點。
要求:找到從起點到終點的所有路線。
思路:我們的目的為了到達終點,所以一定要向著終點的方向出發。
因為迷宮的終點在起點的右下角。
所以我們選擇路徑時先考慮向下走,
走不通考慮向右走,
走不通考慮向上,
最後考慮向左。
這樣就會總有一次到達終點。
思路
1、將“小人”放到起點。
2、判斷這個方向是否能走,(起始方向向下)
(1)如果能走,走這條路,並記錄這條路已經被走過了
(2)如果不能走,
(a)換個方向,重複步驟 2。如果4個方向都不能走,退回上一步的位置,擦掉這條路被走過的記錄,並重復步驟2。
3、如果下一步的座標是終點座標,說明一條路徑已經誕生了。輸出這條路徑。並退回上一步,重複步驟2中的(a),繼續探索下一條路徑。
思考


什麼時候“小人”將所有路徑走完?
“小人”將起點向上開始走到終點的路徑都走完。(此題的迷宮起點向上和向左是沒有路的,所以應該是“小人”從起點開始向右走過的路徑都走完)
演算法實現

首先宣告一個數組用來儲存方向:

int move[4][2] = { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } };//分別代表向下、向右、向上、向左

當前位置的座標加上指定的陣列元素,就是下一步的座標。
定義迷宮:

Maze[9][10];

為了記錄走過的路:定義一個迷宮副本:

copyMaze[9][10];

記錄路線(每一步的座標):

way[100][2
] = { { 1, 1 } };//用來儲存路線(將起點座標新增進去)

約定:
迷宮陣列中:
牆為0、路為-1。
具體實現方法:

#include<stdlib.h>
#include<stdio.h>
#include<windows.h>
int Maze[9][10] = { 0 };
int move[4][2] = { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } };//分別代表向下、向右、向上、向左
int way[100][2] = { { 1, 1 } };//用來儲存路線(將起點座標新增進去)
int copyMaze[9
][10] = { 0 };//用來記錄走過的路 int top = 0;//用來記錄步數,並用來指向最後一步的座標 int count = 0;//用來統計有多少種走法 //製作迷宮路線 void makeAMap(){ //製作迷宮的路線 Maze[1][1] = Maze[1][2] = -1; Maze[2][1] = Maze[2][2] = Maze[2][3] = -1; Maze[3][1] = Maze[3][2] = Maze[3][3] = Maze[3][4] = Maze[3][5] = Maze[3][6] = -1; Maze[4][3] = Maze[4][1] = Maze[4][4] = Maze[4][6] = -1; Maze[5][1] = Maze[5][4] = Maze[5][6] = Maze[5][7] = Maze[5][8] = -1; Maze[6][1] = Maze[6][2] = Maze[6][4] = Maze[6][5] = Maze[6][6] = Maze[6][8] = -1; Maze[7][6] = Maze[7][7] = Maze[7][8] = -1; } //將路徑新增到迷宮中 void addWay(){ int go = top; Maze[1][1] = 1; for (int tag = top; tag > -1; tag--){ Maze[way[tag][0]][way[tag][1]] = 1 + go--; } } //在迷宮刪除上一條路徑 void delWay(){ for (int tag = top; tag > -1; tag--){ Maze[way[tag][0]][way[tag][1]] = -1; } } //列印迷宮 void printMap(){ printf("第%d組\n", ++count); int num = 0; unsigned int block = 32936; unsigned int blank = 8224; addWay(); printf(" 0 1 2 3 4 5 6 7 8 9\n"); for (int i = 0; i < 9; i++){ printf("%d ", num++); for (int j = 0; j < 10; j++){ if (Maze[i][j] == 0){ printf("%s", &block); } else if (Maze[i][j] == -1){ printf("%s", &blank); } else{ printf("%2d", Maze[i][j]); } } printf("\n"); } printf("\n\n"); delWay(); } void maze(int x, int y){ for (int i = 0; i < 4; i++){ int a = x + move[i][0]; int b = y + move[i][1]; if (Maze[a][b] && !copyMaze[a][b]){ //如果有路,並且沒有被走過 copyMaze[a][b] = 1;//走這條路 //記錄這條路已經被走過了 way[++top][0] = a; way[top][1] = b; if (a == 7 && b == 8){ printMap(); } else{ maze(a, b); } //回到上一步,並擦除這一步的痕跡 top--; copyMaze[a][b] = 0; } } } int main(void){ makeAMap(); copyMaze[1][1] = -1; maze(1,1); system("pause"); return 0; }

除錯結果:
這個迷宮一共有56種走法:
第1種:
這裡寫圖片描述
第56種:
這裡寫圖片描述
注意第二部的位置,以此驗證思考題。