关于栈与递归求解迷宫与迷宫最短路径问题

一、栈实现迷宫问题:

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

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值