迷宮(回溯演算法)
阿新 • • 發佈:2018-12-31
要想解決迷宮問題,首先搞明白八皇后,迷宮問題是回溯和貪心的產物。
題目:現有一個迷宮如圖:
黃色五角星為迷宮的起點,紅色五角星為迷宮的終點。
要求:找到從起點到終點的所有路線。
思路:我們的目的為了到達終點,所以一定要向著終點的方向出發。
因為迷宮的終點在起點的右下角。
所以我們選擇路徑時先考慮向下走,
走不通考慮向右走,
走不通考慮向上,
最後考慮向左。
這樣就會總有一次到達終點。
思路
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種:
注意第二部的位置,以此驗證思考題。