迷宫求解(栈的应用)

最近遇到了一个较难的算法题——迷宫求解,刚把栈与队列学完,看完题面之后感觉有点想法,却又一头雾水。
有些问题看着简单但执行起来很难,而有些问题看上去很难但执行起来,更难。

迷宫求解

时间限制: 1 Sec | 内存限制: 128 MB

描述:
有一个 10 x 10 的迷宫,起点是‘S’,终点是‘E’,墙是‘#’,道路是空格。一个机器人从起点走到终点。当机器人走到一个通道块,前面已经没有路可走时,它会转向到当前面向的右手方向继续走。如果机器人能够过,则留下足迹‘*’,如果走不通,则留下标记‘!’。请你模拟机器人的走法输出最终的状态。

样例输入

##########
#S #   # #
#  #   # #
#    ##  #
# ###    #
#   #    #
# #   #  #
# ### ## #
##      E#
##########

样例输出

##########
#**#!!!# #
# *#!!!# #
#**!!##  #
#*###    #
#***#    #
# #***#  #
# ###*## #
##   ****#
##########

算法框架,基本思路啊就是,
把迷宫中的每一块当成一种元素类型一个,然后利用栈的结构特点,让机器人一步一步的探索。
如果可行,就向前迈进并留下一个脚印,同时将这一块压入栈中。如果探索到某一步时发现四周无路可去(也就是可行方格块),就退一步即元素出栈,然后再对当前位置寻找可行路径。
就是这样一步一步的探索,一点一点的入栈出栈,留下脚印、标记,直到走到终点,才停下脚步,绘制了这张迷宫路径图!

在开始描述算法框架之前,需要用到几个函数,分别是可行判断、留下脚印、迈步探索、死路标记

可行判断

//判断下一步的可行状态 
bool Pass(MazeType maze, PosType curpos){
	return maze.arr[curpos.r][curpos.c]==' ' || maze.arr[curpos.r][curpos.c]=='S'
		|| maze.arr[curpos.r][curpos.c]=='E';
}

留下脚印

//留下脚印 
int FootPrint(MazeType &maze, PosType curpos){
		maze.arr[curpos.r][curpos.c]='*';
	return 1;
}

迈步探索

//探索下一步 
PosType NextPos(PosType curpos, int di){ 
	PosType pos=curpos;
	switch(di)
	{
		case 1: pos.c++; break;		//向右 
		case 2: pos.r++; break;		//向下 
		case 3: pos.c--; break;		//向左 
		case 4: pos.r--; break;		//向上 
	}
	return pos;  
}

死路标记

//死路标记
int MarkPrint(MazeType &maze, PosType curpos){
	maze.arr[curpos.r][curpos.c]='!';
	return 1;
}

这些函数原型如果设定完成,这道题的准备工作就完成了,再利用上述的算法框架将探索过程的函数原型还原,使其各函数间分工合作,即可完成最终的路径图。

完整代码如下

#include<stdio.h> 
#include<stdlib.h>
#include<string.h> 
#define Maxsize 1010 
#define Increment 100
typedef struct{
   int r, c;      		//行号和列号
}PosType;
typedef struct{
  int ord;       		//路径序号
  PosType seat; 		//坐标位置
  int di;            	//下一步方向
}SElemType;           	//新定义元素类型
typedef struct{
	int c;
	int r;
   char arr[10][11];
}MazeType; 				//定义迷宫类型(二维字符数组)
typedef struct{ 
	SElemType *base;
	SElemType *top;
	int stacksize; 
}SqStack;
//构建 
int Init(SqStack &S){
	S.base=(SElemType *)malloc(Maxsize*sizeof(SElemType));
	if(!S.base)	return 0;
	S.top=S.base;
	S.stacksize=Maxsize;
	return 1;
}
//判空 
int Empty(SqStack &S){ 
	if(S.top==S.base) 
		return 1; 
	else 
	return 0; 
} 
//入栈 
int Push(SqStack &S,SElemType x){ 
	if(S.top-S.base>=S.stacksize){
		S.base=(SElemType *)realloc(S.base,
			(S.stacksize+Increment)*sizeof(SElemType));
			if(!S.base)
				return 0;
		S.top=S.base+S.stacksize;
		S.stacksize+=Increment;
	} 
	*S.top++=x;
	return 1;
} 
//出栈 
int Pop(SqStack &S, SElemType &x){ 
	if(S.top==S.base)	return 0;
	x=*--S.top;
	return 1;
}
//判断下一步的可行状态 
bool Pass(MazeType maze, PosType curpos){
	return maze.arr[curpos.r][curpos.c]==' ' || maze.arr[curpos.r][curpos.c]=='S'
		|| maze.arr[curpos.r][curpos.c]=='E';
}
//留下脚印 
int FootPrint(MazeType &maze, PosType curpos){
		maze.arr[curpos.r][curpos.c]='*';
	return 1;
}
//探索下一步 
PosType NextPos(PosType curpos, int di){ 
	PosType pos=curpos;
	switch(di)
	{
		case 1: pos.c++; break;		//右 
		case 2: pos.r++; break;		//下 
		case 3: pos.c--; break;		//左 
		case 4: pos.r--; break;		//上 
	}
	return pos;  
}
//死路标记 
int MarkPrint(MazeType &maze, PosType curpos){
	maze.arr[curpos.r][curpos.c]='!';
	return 1;
}
//在地图上探索路径 
int MazePath(MazeType &maze, PosType start, PosType end){
	SqStack S;
	PosType curpos;
	int curstep;
	SElemType e;
	Init(S);
	curpos=start;		//当前位置赋值为入口 
	curstep=1;			//迈出第一步 
	do
	{
		if(Pass(maze, curpos))		//判通 
		{
			FootPrint(maze, curpos);	//留下脚印 
			e.di = 1;
            e.ord = curstep;
            e.seat = curpos; 
			Push(S, e);						//入栈即加入路径 
			 if(curpos.c == end.c &&curpos.r == end.r )
				return 1;
			curpos=NextPos(curpos, e.di);		//先向右探索 
			curstep++;			//迈出去 
		}
		else
		{
			if(!Empty(S))
			{
				Pop(S, e);
				while(e.di==4 && !Empty(S)) 
				{
					MarkPrint(maze, e.seat);	//留下死路标记  
					Pop(S, e);			//逐步退回 
				}
				if(e.di<4)				//对另外三个方向进行探索 
				{
					e.di++;
					Push(S, e);			//入栈即已切换方向 
					curpos=NextPos(e.seat, e.di);	//当前位置赋值为该方向的邻块 
				}
			}
		}
	} while(!Empty(S));
	return 0;
} 
int main()
{
	int i,j;
	MazeType maze;
	maze.r=10, maze.c=10;
	for(i=0; i<maze.r; i++)
	{	
		for(int j=0;j<maze.c; j++)
			scanf("%c", &maze.arr[i][j]);
		getchar();		//缓冲区吃掉回车 
	}
	PosType start, end;	//定义入口出口 
	for(i=0; i<10; i++)		//遍历找到入口出口的坐标 
	{
		for(j=0; j<10; j++)
		{
			if(maze.arr[i][j]=='S')
			{
				start.r=i;
				start.c=j;
			}
			if(maze.arr[i][j]=='E')
			{
				end.r=i;
				end.c=j;
			}
		}
	}
	MazePath(maze, start, end);			//开始寻求路径	
	for(i=0; i<maze.r; i++)			//打印最终的迷宫状态 
	{
		for(j=0; j<maze.c; j++)
			printf("%c", maze.arr[i][j]);
		printf("\n");
	}
	return 0; 
}

注释:

首先:

在迈步探索那个函数里列举了四中迈步方向,这里顺时针逆时针方向的选择是要根据题目要求设定的,观察样例可以看出,机器人是从右开始顺时针依次迈出脚步的。
第二:

在提交到平台判机时,要勾选C++,如果选择C语言,会报出编译错误,提示是函数原型里面的 & 出现问题。

最后吧

还是想说一句,这道题让我第一次接触到了 dfs(深度优先搜索),写得本萌新元气大伤,真是,一如算法深似海。。。

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值