一、栈实现迷宫问题:
问题描述:用一个二维数组模拟迷宫,其中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;
}