一、栈实现迷宫问题:
问题描述:用一个二维数组模拟迷宫,其中1为墙,0为通路,用栈方法判断迷宫是否有出口,下图为简单模拟的迷宫:
思想:
1.首先给出入口点,如上图入口点坐标为{2,0};
2.从入口点出发,在其上下左右四个方向试探,若为通路(值为0)时,则向前走,并将每次通路结点入栈(push)保存和标记走过的路为2;
3.当四个方向都没有通路时,则开始回溯,将栈中保存的结点开始pop,并将每个pop位置标记为3,直到在一个位置重新找到新的路,若没有新路,栈最终将为空,即迷宫没有出口;
4.当栈不为空,并且如在上图例子中找到位置{9,2},即其横坐标=行数-1时,则找到迷宫出口,此时栈中保存着这条通路路径。
代码实现:
#include <iostream> #include <cstdlib> #include <assert.h> #include <stack> using namespace std; const size_t N=10; struct Pos { int _row; int _col; }; bool CheakIsAccess(int *maze,size_t n,Pos pos) //判断每走一次是否为通路(栈) { if((maze[pos._row*n+pos._col]==0)&&(pos._row>=0&&pos._row<n)&&(pos._col>=0&&pos._col<n)) { return true; } return false; } bool GetMazePath(int *maze,size_t n,Pos entry,stack<Pos> &path) //栈方法判断迷宫是否有出口 { assert(maze); Pos cur=entry; //cur保存当前位置 path.push(cur); Pos next=cur; //next保存下一个位置 while(!path.empty()) { cur=path.top(); maze[cur._row*n+cur._col]=2; //标记走过的路 if(cur._row==n-1) //找到一条通路 { return true; } //试探法:上下左右判断是否有通路 //上 next=cur; next._row-=1; if(CheakIsAccess(maze,n,next)) { path.push(next); continue; } //右 next=cur; next._col+=1; if(CheakIsAccess(maze,n,next)) { path.push(next); continue; } //下 next=cur; next._row+=1; if(CheakIsAccess(maze,n,next)) { path.push(next); continue; } //左 next=cur; next._col-=1; if(CheakIsAccess(maze,n,next)) { path.push(next); continue; } maze[cur._row*n+cur._col]=3; //若四个方向都没有通路为死路时标记为3 path.pop(); //并且回溯 } return false; } void GetMaze(int *maze,size_t N) //获取迷宫 { FILE *fout=fopen("MazeMap.txt","r"); //在文件中读取 assert(fout); for(size_t i=0;i<N;++i) { for(size_t j=0;j<N;) { int value=fgetc(fout); if(value=='1'||value=='0') { maze[i*N+j]=value-'0'; ++j; } else if(value==EOF) { cout<<"Error(maze)"<<endl; fclose(fout); return; } } } fclose(fout); } void PrintMaze(int *maze,size_t N) //打印迷宫 { for(size_t i=0;i<N;++i) { for(size_t j=0;j<N;++j) { cout<<maze[i*N+j]<<" "; } cout<<endl; } } void TestMaze() { int maze[N][N]; GetMaze((int*)maze,N); PrintMaze((int*)maze,N); //打印迷宫 cout<<endl; stack<Pos> path; Pos entry={2,0}; //入口 maze[entry._row][entry._col]=2;//标记入口先为2 //栈寻找迷宫是否有出口 GetMazePath((int*)maze,N,entry,path); PrintMaze((int*)maze,N); cout<<"迷宫是否有通路?"<<!path.empty()<<endl; } int main() { TestMaze(); system("pause"); return 0; }结果显示:
栈中保存路径:
二、递归实现迷宫最短路径问题
问题描述:迷宫中有几条通路路径,用递归求解迷宫中的最短路径,如下迷宫图:
思想:
1.找到入口点,上下左右试探,试探时若下一个位置为0或者若下一个位置值大于原位置值加1,则表示为一个通路,若找到通路则递归调用自身,每走一次标记其值为前一个值加1,并将每个位置入栈保存;
2.若找到通路将此时原栈中保存的路径保存到另一个空栈ShortPath中,原栈则pop,并且递归结束返回;
3.如上图返回到位置{6,7},其左边为0为通路,在开始递归调用,调用到{6,6},值变为18,其左边位置为0通路,调用到{6,5},值变为19,下一个位置值都不大于原位置值加1,在此递归结束原路返回;
4.再返回到位置{6,4},其右边位置值大于{6,4}位置值加1,为通路,在此开始递归调用,每次下一个位置值都大于原位置值加1,再此找到第二条通路;
5.将此时栈与ShortPath的个数size比较,若小于,则在将此时栈内容赋于ShortPath中;
6.原栈再次pop,递归又一次结束原路返回,最终到入口点,原栈为空,ShortPath保存路径为迷宫最短路径。
代码实现:
bool CheakIsAccess(int *maze,size_t n,Pos cur,Pos next) //判断每走一次是否为通路(递归) { if((maze[next._row*n+next._col]==1)||(next._row<0||next._row>=n)||(next._col<0||next._col>=n)) { return false; } if(maze[next._row*n+next._col]==0) { return true; } if(maze[next._row*n+next._col]>maze[cur._row*n+cur._col]+1)//若next位置值大于cur位置值加1则表示为一个新路 { return true; } return false; } void GetMazePathR(int *maze,size_t n,Pos entry,stack<Pos> &path,stack<Pos> &ShortPath) //递归方法求解最短路径 { assert(maze); Pos cur=entry; path.push(cur); Pos next=cur; if(cur._row==n-1) { if(ShortPath.empty()||path.size()<ShortPath.size()) //将最短路径给ShorytPath栈 { ShortPath=path; } path.pop(); return; } //上 next=cur; next._row-=1; if(CheakIsAccess(maze,n,cur,next)) { maze[next._row*n+next._col]=maze[cur._row*n+cur._col]+1; //每走一次将现值标记为前一个值加1 GetMazePathR((int*)maze,N,next,path,ShortPath); } //右 next=cur; next._col+=1; if(CheakIsAccess(maze,n,cur,next)) { maze[next._row*n+next._col]=maze[cur._row*n+cur._col]+1; GetMazePathR((int*)maze,N,next,path,ShortPath); } //下 next=cur; next._row+=1; if(CheakIsAccess(maze,n,cur,next)) { maze[next._row*n+next._col]=maze[cur._row*n+cur._col]+1; GetMazePathR((int*)maze,N,next,path,ShortPath); } //左 next=cur; next._col-=1; if(CheakIsAccess(maze,n,cur,next)) { maze[next._row*n+next._col]=maze[cur._row*n+cur._col]+1; GetMazePathR((int*)maze,N,entry,path,ShortPath); } path.pop(); } void TestMaze() { int maze[N][N]; GetMaze((int*)maze,N); PrintMaze((int*)maze,N); //打印迷宫 cout<<endl; stack<Pos> path; stack<Pos> ShortPath; //(递归实现中)保存栈中最短路径 Pos entry={2,0}; //入口 maze[entry._row][entry._col]=2;//标记入口先为2 //递归寻找迷宫最短路径 GetMazePathR((int*)maze,N,entry,path,ShortPath); PrintMaze((int*)maze,N); cout<<"迷宫是否有通路?"<<!ShortPath.empty()<<endl; }