UVA532 Dungeon Master反思

本文深入解析UVA532 DungeonMaster题目,通过三维BFS算法实现迷宫逃脱路径寻找,强调了标记已走路径的重要性,避免重复访问同一位置,分享了AC代码及算法实践心得。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:UVA532 Dungeon Master

类型:bfs 队列 三维bfs

主要错误:标记已走过的点不及时

  • 第一次标记的位置如下注释,在判断可达到后标记,标的是当前的位置(我在想啥呢),会出现两个问题:
    1. 如果当前位置没有路可走,那么当前位置不会被标记
    2. 只标记当前位置会导致位置重复压入,原则上说每个位置只能让它压入一次,所以必须一旦压入就立马标记已走过
while(que.size())
		{
			A a=que.front();
			que.pop();
			for(int i=-1;i<=1;i+=2)
			for(int j=0;j<3;j++)
			{
				int nx=a.x+i*next1[j][0],ny=a.y+i*next1[j][1],nz=a.z+i*next1[j][2];
				if(nx>=0&&nx<n&&ny>=0&&ny<m&&nz>=0&&nz<l&&maze[nz][nx][ny]!='#')
				{
					if(maze[nz][nx][ny]=='E')
					{
						cout<<"Escaped in "<<ans[a.z][a.x][a.y]+1<<" minute(s)."<<endl;
						goto end;
					}
					ans[nz][nx][ny]=ans[a.z][a.x][a.y]+1;
					maze[a.z][a.x][a.y]='#';	//这里
					que.push(A(nx,ny,nz));
				}
			}
		}
  • 第二次标记和第一次的错误2一样,仍然会导致相同元素的重复压入
while(que.size())
		{
			A a=que.front();
			que.pop();
			maze[a.z][a.x][a.y]='#';//这里
			for(int i=-1;i<=1;i+=2)
			for(int j=0;j<3;j++)
			{
				int nx=a.x+i*next1[j][0],ny=a.y+i*next1[j][1],nz=a.z+i*next1[j][2];
				if(nx>=0&&nx<n&&ny>=0&&ny<m&&nz>=0&&nz<l&&maze[nz][nx][ny]!='#')
				{
					if(maze[nz][nx][ny]=='E')
					{
						cout<<"Escaped in "<<ans[a.z][a.x][a.y]+1<<" minute(s)."<<endl;
						goto end;
					}
					ans[nz][nx][ny]=ans[a.z][a.x][a.y]+1;
					que.push(A(nx,ny,nz));
				}
			}
		}
  • 最后记得这种多组测试数据放一起的题,每次要还原数组之类的,每次做完检查一下,不要理所当然觉得数据会进行覆盖。
  • AC代码:
#include<iostream>
#include<queue>
using namespace std;
const int MAX_N=32;
struct A
{
	int x,y,z;
	A(int x,int y,int z):x(x),y(y),z(z){}
	A(){}
};
int next1[3][3]={{1,0,0},{0,1,0},{0,0,1}};
char maze[MAX_N][MAX_N][MAX_N];
int ans[MAX_N][MAX_N][MAX_N];
int main()
{
	ios::sync_with_stdio(false);
	int l,n,m;
	while(cin>>l>>n>>m&&(l||m||n))
	{
		A begin,end;
		for(int i=0;i<l;i++)
			for(int j=0;j<n;j++)
				for(int k=0;k<m;k++)
				{
					cin>>maze[i][j][k];
					ans[i][j][k]=0;
					if(maze[i][j][k]=='S')begin.x=j,begin.y=k,begin.z=i,maze[i][j][k]='#';
					if(maze[i][j][k]=='E')end.x=j,end.y=k,end.z=i;
				}
		queue<A> que;
		que.push(begin);
		int a1=-1;
		while(que.size())
		{
			A a=que.front();
			que.pop();
			if(a.x==end.x&&a.y==end.y&&a.z==end.z)
			{
				a1=ans[a.z][a.x][a.y];
				break;
			}
			for(int i=-1;i<=1;i+=2)
			for(int j=0;j<3;j++)
			{
				int nx=a.x+i*next1[j][0],ny=a.y+i*next1[j][1],nz=a.z+i*next1[j][2];
				if(nx>=0&&nx<n&&ny>=0&&ny<m&&nz>=0&&nz<l&&maze[nz][nx][ny]!='#')
				{
					maze[nz][nx][ny]='#';
					ans[nz][nx][ny]=ans[a.z][a.x][a.y]+1;
					que.push(A(nx,ny,nz));
				}
			}
		}
		if(a1!=-1)cout<<"Escaped in "<<a1<<" minute(s)."<<endl;
		else cout<<"Trapped!"<<endl;
	}
	return 0;
}

总结

  1. 大部分的题目都是压入就标记,记住这一点就对了,压入->标记
  2. 可移动方向也很容易出错,要注意
这道题出了很多问题,说明我对bfs算法掌握还不够熟练,要对该算法多加练习
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值