用C語言解決迷宮問題
#include <stdio.h> #include <stdlib.h> #define ROW 10 #define COL 10 /*迷宮中位置信息*/ typedef struct position { int x; int y; }position; /*在迷宮中的當前位置的信息,也是入棧的基本元素*/ typedef struct SElem { int di; position seat; }SElem; /*鏈式棧中節點的定義*/ typedef struct position_stack { SElem p; struct position_stack *next; }*Stack_pNode,Stack_Node; void InitStack(Stack_pNode *Link) { *Link = NULL; } void push(Stack_pNode *Link,SElem e) { Stack_pNode new_SElem = (Stack_pNode)calloc(1,sizeof(Stack_Node)); new_SElem->p = e; new_SElem->next = NULL; if (*Link == NULL) *Link = new_SElem; else { new_SElem->next = *Link; *Link = new_SElem; } } int pop(Stack_pNode *Link,SElem *e) { if (*Link == NULL) return 0; *e = (*Link)->p; Stack_pNode q = *Link; *Link = (*Link)->next; free(q); return 1; } int top(Stack_pNode Link, SElem *e) { if (Link == NULL) return 0; *e = Link->p; return 1; } int empty(Stack_pNode Link) { if (Link == NULL) return 1; else return 0; } int reverse(Stack_pNode *Link) { Stack_pNode p, q, r; if (*Link == NULL || (*Link)->next == NULL) return 0; r = *Link; p = (*Link)->next; q = NULL; while (p){ r->next = q; q = r; r = p; p = p->next; } r->next = q; *Link = r; } void print(Stack_pNode Link) { Stack_pNode r = Link; while (r){ printf("(%d,%d) -> ",r->p.seat.x,r->p.seat.y); r = r->next; } printf("exit\n"); } int curstep = 1;/*紀錄當前的足跡,填寫在探索前進的每一步正確的路上*/ /*迷宮地圖。1代表墻的位置,0代表可行的路,周圍有一圈墻*/ int m[ROW+2][COL+2] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; /*方向優先級設定。依次為當前位置的右,下,左。上,在位置信息中。保存有本次 前進的方向--數組的下標*/ position dir_set[4] = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } }; /*推斷當前位置是否可行。即推斷是路。還是墻*/ int pass(position p) { if (m[p.x][p.y]) return 0; else return 1; } /*將當前的步數填寫在走的每一步正確的路上,當發現走不通時,會把當時寫的信息 用‘1’抹掉,代表走不通。*/ void footPrint(position p) { m[p.x][p.y] = curstep; } /*計算下一步的坐標。di代表方向。本函數僅僅負責計算下一步坐標。不推斷優先級*/ void nextPos(position *p, int di) { (*p).x += dir_set[di].x; (*p).y += dir_set[di].y; } /*如上面的footPrint()凝視中提到的,當發現當前路走不通時,會用‘1’把走不通的 路堵上。
*/ void markPrint(position p) { m[p.x][p.y] = 1; } /*迷宮程序的主函數。形參是一個指向不帶頭節點的棧的指針的指針,一個開始位置 ,一個結束位置*/ int find_path(Stack_pNode * Maze_stack,position start,position end) { position curpos = start;/*定義一個位置變量。用來保存當前的位置信息 */ SElem e;/*棧的元素。包含位置信息,和前進的方向*/ do { if (pass(curpos)){ /*假設當前節點是路,則要將當前節點入棧。 並計算下一步前進方向*/ footPrint(curpos);/*在前進節點上紀錄當前的步數*/ e.seat = curpos;/*保存位置信息*/ e.di = 0;/*保存方向信息。默覺得向右*/ push(Maze_stack, e);/*將位置信息入棧*/ ++curstep;/*步數加1*/ if (curpos.x == end.x && curpos.y == end.y)/*假設當 前節點是出口。則返回運行成功的標識*/ return 1; nextPos(&curpos, e.di);/*計算下一步的坐標。是依據當 前位置信息計算的,即已經入棧了的信息*/ } else{/*假設當前節點是墻。則須要從棧取出之前走過的路,即沿原 路返回,在返回的過程中,還要不斷的推斷有沒有其它的路*/ if (!empty(*Maze_stack)){/*假設棧中有元素*/ pop(Maze_stack,&e); --curstep; while (e.di == 3 && !empty(*Maze_stack)){/* 邊向前回溯,邊推斷是否有其它的路可走*/ markPrint(e.seat);/*用"墻"覆蓋之前 填寫的步數信息*/ pop(Maze_stack,&e); --curstep; } if (e.di < 3){/*當找到了一個還有其它的路可 走之前走過的一個方塊(最壞的情況是回到起始位置)*/ ++e.di;/*按優先級改變之前的行走方向 */ push(Maze_stack, e);/*再次入棧*/ ++curstep;/*再次將步數加1*/ curpos = e.seat;/*再次紀錄如今的位 置*/ nextPos(&curpos, e.di);/*再次計算下 次的方向,有了以上的準備,即將進行下一次的循環*/ }//end if }//end if }//end else } while (!empty(*Maze_stack)); return 0; } /*打印迷宮*/ void printMaze() { int i, j; for (i = 0; i < ROW+2; ++i) { for (j = 0; j < COL+2; ++j){ printf("%2d ", m[i][j]); } printf("\n"); } } int main() { //stack_test(); position start = { 1, 1 };/*迷宮入口*/ position end = { 10, 10 };/*迷宮出口*/ Stack_pNode maze_stack;/*聲明一個棧,一會兒用來存放在迷宮中走過的位 置*/ InitStack(&maze_stack);/*初始化棧*/ if (find_path(&maze_stack, start, end)){ reverse(&maze_stack);/*因為棧中存放的是倒置的信息,須要將棧 倒置*/ print(maze_stack);/*打印帶有走過的步數信息的迷宮地圖*/ } else{ printf("Has no way to out of the maze.\n"); } printMaze(); return 0; }
用C語言解決迷宮問題