迷宮求解 呼叫棧,及遞迴實現
阿新 • • 發佈:2019-01-01
迷宮求解
1. 首先要有一張迷宮地圖,地圖由兩部分組成:
(1)一是迷宮中各處的位置座標,
(2)二是迷宮各位置處的狀態資訊,即該處是牆還是路
1)迷宮地圖是6*6的,即二維陣列是6行6列的。(2)在迷宮中用0表示牆,用1表示路
給定一個地圖
初始化地圖
3 #define ROW 6
4 #define COL 6
5
6 //定義一個倉庫儲存地圖和路徑
7 typedef struct Warehouse
8 {
9 int map[ROW][COL];
10 }Warehouse;
11
12 //表示地圖中的點的橫列值
13 typedef struct Point
14 {
15 int row;
16 int col;
17 }Point;
18 //地圖進行初始化
19 void MapInit(Warehouse*house)
20 {
21 if(house==NULL)
22 {
23 return ;
24 }
25 int tmp[ROW ][COL]=
26 {
27 {0,1,0,0,0,0},
28 {0,1,1,1,0,0},
29 {0,1,0,0,0,0},
30 {0,1,1,0,0,0},
31 {0,1,0,0,0,0},
32 {0,1,0,0,0,0}
33 };
34 int row=0;
35 for(;row<ROW;++row)
36 {
37 int col=0;
38 for(;col<COL;++col)
39 {
40 //對地圖中的點進行初始化
41 house->map[row][col]=tmp[row][col];
42 }
43 }
44 }
判斷當前點能否落腳
47 //判斷能否落腳
48 int CanStay(Warehouse* house, Point cur)
49 {
50 //落腳點在地圖之外不能落腳
51 if(cur.row<0||cur.row>ROW||cur.col<0||cur.col>COL)
52 {
53 return 0;
54 }
55 //約定,二維陣列中值為1可以落腳
56 if(house->map[cur.row ][cur.col]==1)
57 {
58 return 1;
59 }
60 return 0;
61 }
對落腳點進行標記
63 //對落腳點進行標記
64 void Mark(Warehouse* house,Point cur)
65 {
66 if(house==NULL)
67 {
68 return ;
69 }
70 //約定 落腳點值為2
71 house->map[cur.row][cur.col]=2;
72 return ;
73 }
判斷當前點是否為出口
75 //當前點是否為出口
76 int IsExit(Point cur,Point entry)
77 {
78 //入口點不能為出口
79 if(cur.row==entry.row&&cur.col==entry.col)
80 {
81 return 0 ;
82 }
83 if(cur.row==0||cur.row==ROW-1||cur.col==0||cur.col==COL-1)
84 {
85 return 1;
86 }
87 return 0;
88 }
從入口進入迷宮尋找出口
//根據入口點和迷宮地圖找迷宮的出口
void Path(Maze* maze,Point entry);
方法一 遞迴實現
實現思想:
因為每經過一處,都要呼叫該遞迴函式,即將經過的位置入棧,但是該位置是否能走,還需要在進行判斷。所以在遞迴函式函式中需要對各個位置進行判斷:
(1)該位置能否落腳,如果不能落腳,就直接結束函式呼叫。
(2)如果能落腳,標記該位置(約定為2),表示走過。
(3)判斷該位置是否是出口(規定出口在邊界上),如果是出口列印資訊並返回
(4)如果不是出口,在四周探索(約定順時針,深度優先探索)。將四周點作為新的當前點出入遞迴函式,進行函式呼叫。
(5)當四周點都已經探索完了,說明探索結束。原路返回探索上一個岔路口的其他路線。此時,直接結束函式呼叫就表示將當前位置出棧了。
90 //輔助函式判斷是否為合法路徑
91 void _Path(Warehouse* house,Point cur, Point entry)
92 {
93 if(house==NULL)
94 {
95 return ;
96 }
97 printf("(%d%d)",cur.row,cur.col);
98 //判斷當前點是否能落腳
99 if(CanStay(house,cur)==0)
100 {
101 return ;
102 }
103 //如果可以落腳進行標記
104 Mark(house,cur);
105 //判斷當前點是否為出口
106 if(IsExit(cur,entry)==1)
107 {
108 printf("找到一條出口\n");
109 return ;
110 }
111 //如果不是出口對四周進行探索(例如順時針)
112 Point up;
113 cur.row-=1;
114 _Path(house,up,entry);
115
116 Point right;
117 cur.col+=1;
118 _Path(house,right,entry);
119
120 Point down;
121 cur.row+=1;
122 _Path(house,down,entry);
123
124 Point left;
125 cur.col-=1;
126 _Path(house,left,entry);
127 }
128
129 void Path(Warehouse* house, Point entry)
130 {
131 if(house==NULL)
132 {
133 return ;
134 }
135 _Path(house,entry,entry);
136 return ;
137 }
方法二 借用棧實現
Path函式的實現思路如下:
(1)定義一個棧儲存走過的位置資訊
(2)從入口點開始探索,是否落腳,若能落腳,標記併入棧
(3)取棧頂元素判斷若棧為空,說明回溯結束沒有出口
(4)若不為空則判斷棧頂元素是否為出口點,若出口點直接列印返回
(5)若棧頂元素不是出口點,就順時針探測該棧頂元素的四周。
(6)依次判斷若落腳(則標記,併入棧)
(8)如果四周的點都探測完了還沒找到出口,就出棧頂元素,繼續探測上一個位置的四周點。
155 //方法二借用棧實現判斷出口
156 void Pathstack(Warehouse* house,Point entry)
157 {
158 if(house==NULL)
159 {
160 return;
161 }
162
163 //定義棧,對其初始化
164 SeqStack stack;
165 SeqStackInit(&stack);
166
167 //若能落腳,標記,入棧
168 if(CanStay(house,entry)==0)
169 {
170 return ;
171 }
172 Mark(house,entry);
173 SeqStackPush(&stack,entry);
174
175 //迴圈判斷
176 while(1)
177 {
178
179 Point cur;
180 int ret=SeqStackTop(&stack);
181 if(ret==-1)
182 {
183 printf("沒有找到");
184 return ;
185 }
186 printf("(%d%d)\n",cur.row,cur.col);
187 if(IsExit(cur,entry)==1)
188 {
189 printf("找到一條出口");
190 return ;
191 }
192
193 //如果不是出口,對四周探索(例如順時針)
194 Point up;
195 up.row-=1;
196 if(CanStay(house,up)==1)
197 {
198 Mark(house,up);
199 SeqStackPush(&stack,up);
200 continue;
201 }
202
203 Point right;
204 right.col+=1;
205 if(CanStay(house,right)==1)
206 {
207 Mark(house,right);
208 SeqStackPush(&stack,right);
209 continue;
210 }
211
212 Point down;
213 down.row+=1;
214 if(CanStay(house,down)==1)
215 {
216 Mark(house,down);
217 SeqStackPush(&stack,down);
218 continue;
219 }
220
221 Point left;
222 left.col-=1;
223 if(CanStay(house,left)==1)
224 {
225 Mark(house,left);
226 SeqStackPush(&stack,left);
227 continue;
228 }
229 SeqStackPop(&stack);
230 }
231 }