一個簡單的迷宮演算法
阿新 • • 發佈:2019-01-24
迷宮問題的求解是一個典型的問題,那仫如何找到迷宮的出口?在遇到死衚衕的時候如何返回?如何防止走重複的路程?這就是我們要解決的問題了.
一.設定迷宮
要列印一個簡單的迷宮,我們理所當然的想到了利用二維陣列,在迷宮的實現中我定義了一個MazeMap.txt的檔案用來儲存迷宮,在初始化的時候只需要將該迷宮從mazeMap.txt中讀出來就可以了.
0-路
1-牆
二.如何找到迷宮的通路
(1).如果當前路徑已經走過則要留下標記;如果走到死衚衕也要留下標記,但是要體現回溯,所以這兩種情況的標記最好不同
(2).找迷宮路徑的可通路可理解為使用試探法.
即在一個結點的上,下,左,右四個方向進行試探,如果某一個方向滿足迷宮位置要求則將該位置壓棧;如果走到死衚衕此時該位置的四個方向都不可通(之前已經將走過的路標記為2),我們只需要將該位置出棧即可.
(3).判斷是否走出迷宮.
因為迷宮的出口只可能在邊界,我們可以認為三個方向都可能存在出口.所以在判斷是否走出迷宮的時候,我們可以在除了入口的那一面都進行判斷.
迷宮問題也是棧的應用場景之一
三.實現場景.(體現回溯和找到迷宮出口)
在迷宮中用到的棧是我自己寫的.
template<typename T> class Stack { public: Stack() :_ptr(NULL) ,_size(0) ,_capacity(0) {} ~Stack() { if(_ptr != NULL) { delete[]_ptr; _ptr=NULL; } _size=0; _capacity=0; } void Push(const T& x) { _CheckCapacity(); _ptr[_size++]=x; } void Pop() { assert(_size >= 0); _size--; } bool Empty() { return _size == 0; } T& Top() { return _ptr[_size-1]; } size_t Size() { return _size; } protected: void _CheckCapacity() { if(_size == _capacity) { int NewCapacity=2*_capacity+2; T *tmp=new T[NewCapacity]; //memcpy(tmp,_ptr,_size*sizeof(T)); for(int i=0;i<_size;i++) { tmp[i]=_ptr[i]; } delete []_ptr; _ptr=tmp; _capacity=NewCapacity; } } protected: T *_ptr; int _size; int _capacity; };
實現迷宮的基本演算法.
const int N=10; struct Pos { Pos(int row=0,int col=0) :_row(row) ,_col(col) {} int _row; //行 int _col; //列 }; void InitMaze(int *mz) { char tmp; Pos enter; FILE *pf=fopen("MazeMap.txt","r"); assert(pf); for(size_t i=0;i<N;++i) { for(size_t j=0;j<N;) { tmp=fgetc(pf); if(tmp == '0' || tmp == '1') { mz[i*N+j]=tmp-'0'; ++j; } } } } bool CheckReason(int *mz,Pos pos) { if((pos._row >= 0) && (pos._col < N) && (pos._row >= 0) && (pos._col < N) && (mz[pos._row*N+pos._col] == 0)) { return true; //可通路 } return false; //不可通路 } bool FindPath(int *mz,int rows,int cols,Stack<Pos>& s,Pos enter) { s.Push(enter); mz[enter._row*cols+enter._col]=2; while(!s.Empty()) //如果棧為空說明該迷宮無解 { Pos cur=s.Top(); Pos next=cur; if((next._row == 0) || (next._row == rows-1) || (next._col == cols-1)) //判斷是否走出迷宮 { return true; } //上 next._row -= 1; if(CheckReason((int *)mz,next)) { s.Push(next); mz[next._row*cols+next._col]=2; //經過的路置標記,防止走回頭路 continue; } next._row += 1; //右 next._col += 1; if(CheckReason((int *)mz,next)) { s.Push(next); mz[next._row*cols+next._col]=2; continue; } next._col -= 1; //左 next._col -= 1; if(CheckReason((int *)mz,next)) { s.Push(next); mz[next._row*cols+next._col]=2; continue; } next._col += 1; //下 next._row += 1; if(CheckReason((int *)mz,next)) { s.Push(next); mz[next._row*cols+next._col]=2; continue; } next._row -= 1; mz[cur._row*cols+cur._col]=3; //體現回溯 s.Pop(); } return false; } void PrintMaze(int *mz) { for(size_t i=0;i<N;i++) { for(size_t j=0;j<N;j++) { cout<<mz[i*N+j]<<" "; } cout<<endl; } cout<<endl; }
在此迷宮問題中也可以找到走出此迷宮的最優路徑,在這裡用到圖的廣度優先可以解決...