Description
給定迷宮起點和終點,尋找一條從起點到終點的路徑。
|
(0,1) |
|
|
|
|
(2,0) |
起點 (1,1) |
(1,2) |
(1,3) |
(1,4) |
|
(2,0) |
(2,1) |
|
|
(2,4) |
|
(3,0) |
(3,1) |
(3,2) |
|
終點 (3,4) |
|
|
(4,1) |
|
|
|
|
上圖中黃色代表牆,白色代表通路,起點為(1,1),終點為(3,4)。
要求搜尋策略是從起點開始按照“上、下、左、右”四個方向尋找終點,到下一個點繼續按照“上、下、左、右”四個方面尋找,當該結點四個方向都搜尋完,但還沒到終點時,退回到上一個點,直到找到終點或者沒有路徑。
比如上圖從(1,1)開始,向上(0,1)不通,向下到(2,1);到了(2,1)后繼續按“上、下、左、右”四個方面尋找,上已經走過,向下到(3,1);到(3,1)后上已經走過,下和左不通,向右到(3,2);到(3,2)四個方面都不通,回到(3,1)四個方向都不通,再回到(2,1),(1,1);到達(1,1)后下已經走過,左不通,繼續向右走,重復這個過程最后到達(3,4)。
Input
第一行兩個數m和n表示迷宮的行數和列數。迷宮大小不超過100×100
第二行四個數x1,y1,x2,y2分別表示起點和終點的坐標。
接下來是m行n列的數,用來表示迷宮,1表示牆,0表示通路。
Output
從起點到終點所經過的路徑的坐標。如果不存在這樣的路徑則輸出“No Path!”。
Sample Input
5 6 1 1 3 4 1 1 1 1 1 1 1 0 0 0 0 1 1 0 1 1 0 1 1 0 0 1 0 1 1 1 1 1 1 1
Sample Output
(1 1)(1 2)(1 3)(1 4)(2 4)(3 4)
1.思路:
(1)若當前點是終點,dfs函數返回1;
(2)若不是終點,將此點標記為1,對該點4個方向進行搜索,實現方式為定義int dir[4][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} }; 通過一個小循環:
for(int i = 0; i < 4; i++) {
position nextp;
nextp.x = dir[i][0] + now.x;
nextp.y = dir[i][1] + now.y;
......
}
進行搜索;若該點的下一個點nextp不是牆,未走,並且沒有超界則將nextp壓入棧中,遞歸調用dfs,若此過程經過(1)判斷返回了1,說明最終找到了通往終點的路,便可以返回1,結束函數,此時棧中已儲存了通往終點的路徑,
若沒有通路,則彈出棧頂元素,根據遞歸原理該路徑上的所有點都會彈出並標記未走,回溯到之前的點,繼續向其他方向搜索,直到找到終點或遍歷完整個圖。
(3)遍歷整個圖都沒有發現通往終點的路,則輸出“No Path!”。
2.代碼:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <math.h> 5 6 typedef struct { 7 int x; 8 int y; 9 }position; 10 11 typedef struct my_stack { 12 int len; 13 position path[10001];//用數組表示棧內元素 14 }Stack; 15 16 17 /*棧的實現*/ 18 Stack *create_emptystack(); 19 int isempty(Stack *s); 20 void push_stack(Stack *s, position pos); 21 void pop_stack(Stack *s); 22 //position get_top(Stack *s); 23 24 /*dfs*/ 25 int judge(position p); 26 int dfs(Stack *s, position now); 27 28 int a[100][100]; 29 position begin, end; 30 int m, n; 31 32 int main() { 33 scanf("%d%d", &m, &n); 34 scanf("%d%d%d%d", &begin.x, &begin.y, &end.x, &end.y); 35 for(int i = 0; i < m; i++) { 36 for(int j = 0; j < n; j++) 37 scanf("%d", &a[i][j]); 38 } 39 Stack *s = create_emptystack(); 40 push_stack(s, begin); 41 dfs(s, begin); 42 if(s->len == 0) printf("No Path!"); 43 else for(int i = 0; i < s->len + 1; i++) 44 printf("(%d %d)", s->path[i].x, s->path[i].y); 45 return 0; 46 } 47 48 Stack* create_emptystack() { 49 Stack *S; 50 S = (Stack*)malloc(sizeof(Stack)); 51 if(S == NULL) 52 printf("malloc error\n"); 53 else 54 S->len = -1; 55 return S; 56 } 57 58 int isempty(Stack *s) { 59 return s->len == -1; 60 } 61 62 void push_stack(Stack *s, position pos) { 63 if(s->len > 10001) 64 printf("exceed!\n"); 65 else { 66 s->len++; 67 s->path[s->len] = pos; 68 } 69 } 70 71 void pop_stack(Stack *s) { 72 if(!isempty(s)) 73 s->len--; 74 } 75 76 //position get_top(Stack *s) {return s->path[s->len];} 77 78 int judge(position p) { 79 return a[p.x][p.y] == 0 && p.x >= 0 && p.x < m && p.y >= 0 && p.y < n; //沒有走並且沒有超界 80 } 81 82 int dfs(Stack *s, position now) { 83 int dir[4][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} }; //上下左右四個方向 84 if(now.x == end.x && now.y == end.y) return 1; //如果當前節點是終點, 返回1 85 else{ 86 a[now.x][now.y] = 1; //標記已走 87 for(int i = 0; i < 4; i++) { 88 position nextp; 89 nextp.x = dir[i][0] + now.x; 90 nextp.y = dir[i][1] + now.y; 91 if(!judge(nextp)) continue; //如果下一個節點不合法, 那么直接退出 92 push_stack(s, nextp); //先把下一個節點壓入 93 if(dfs(s, nextp)) return 1; //如果子節點中最終可以找到終點, 那么直接結束 94 pop_stack(s); //如果不能, 那么把下一個節點彈出, 並且進行下一個循環 95 } 96 a[now.x][now.y] = 0; 97 return 0; //如果找不到, 那么直接返回0 98 } 99 }
本題的要點是給dfs函數設置返回值來表示是否有到終點的通路。
3.最短路徑(bfs):
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <math.h> 5 6 typedef struct { 7 int x; 8 int y; 9 int pre; //記錄該結點的父結點(來源) 10 }position; 11 12 typedef struct my_queue { 13 position *que; 14 int front; 15 int last; 16 }Queue; 17 18 Queue* create_emptyqueue(); 19 int isempty(Queue *q); 20 void push_queue(Queue *q, position x); 21 void pop_queue(Queue *q); 22 23 int a[100][100]; 24 Queue *bfs(position st); 25 void print(Queue *q, position ans); 26 27 position begin, end; 28 int m, n, flag = 0; 29 30 31 int main() { 32 int i, j; 33 Queue *q; 34 scanf("%d%d", &m, &n); 35 scanf("%d%d%d%d", &begin.x, &begin.y, &end.x, &end.y); 36 begin.pre = -1; 37 for(i = 0; i < m; i++) { 38 for(j = 0; j < n; j++) 39 scanf("%d", &a[i][j]); 40 } 41 q = bfs(begin); 42 if(!flag) printf("No Path!"); 43 else { 44 print(q, q->que[q->front - 1]); 45 printf("(%d %d)", end.x, end.y); 46 } 47 return 0; 48 } 49 50 Queue *create_emptyqueue() { 51 Queue *p; 52 p = (Queue*)malloc(sizeof(Queue)); 53 if(p != NULL) { 54 p->que = (position*)malloc(10000*sizeof(position)); 55 if(p->que != NULL) { 56 p->front = 0; 57 p->last = 0; 58 return p; 59 } 60 else free(p); 61 } 62 return NULL; 63 } 64 65 int isempty(Queue *q) { 66 return q->front == q->last; 67 } 68 69 void push_queue(Queue *q, position x) { 70 if(q->last + 1 == q->front) 71 printf("full\n"); 72 else { 73 q->que[q->last] = x; 74 q->last = q->last + 1; 75 } 76 } 77 78 void pop_queue(Queue *q) { 79 if(q->front == q->last) 80 printf("empty\n"); 81 else 82 q->front = q->front + 1; 83 } 84 85 Queue *bfs(position st) { 86 int pr, i; 87 int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; 88 position former, latter; 89 position t; 90 Queue *q = create_emptyqueue(); 91 former = st; 92 push_queue(q, former); 93 a[former.x][former.y] = 1; 94 while(!isempty(q)) { //隊列不為空,說明可能還有可走的路 95 latter = q->que[q->front]; 96 pr = q->front; 97 pop_queue(q); 98 for(i = 0; i < 4; i++) { 99 t.x = latter.x + dir[i][0]; 100 t.y = latter.y + dir[i][1]; 101 t.pre = pr; //記錄該結點的來源 102 if(t.x == end.x && t.y == end.y) { 103 flag = 1; 104 return q; 105 } 106 if(!a[t.x][t.y] && t.x >= 0 && t.x < m && t.y >= 0 && t.y < n) { 107 push_queue(q, t); 108 a[t.x][t.y] = 1; 109 } 110 } 111 } 112 return q; 113 } 114 115 void print(Queue *q, position ans) { //遞歸輸出 116 if(ans.pre == -1) { 117 printf("(%d %d)", ans.x, ans.y); 118 return ; 119 } 120 else { 121 print(q, q->que[ans.pre]); 122 printf("(%d %d)", ans.x, ans.y); 123 } 124 }