[POJ - 2251 ]B - Dungeon Master

题目阅读

You are trapped in a 3D dungeon and need to find the quickest way out! The dungeon is composed of unit cubes which may or may not be filled with rock. It takes one minute to move one unit north, south, east, west, up or down. You cannot move diagonally and the maze is surrounded by solid rock on all sides.

Is an escape possible? If yes, how long will it take?

生词

​ dungeon [ˈdʌndʒən] n.地牢

​ unit cube n.单位立方体

​ maze [meɪz] n.迷宫

1.“3D地牢”是吓唬人的,可以理解为魔塔游戏,而“单位立方体”不过是可以忽略高度的二维正方形。

2.这里的“东西南北”对应迷宫题的“上下左右”,而这里的“上下”则是“通过同一横纵坐标的通路跨越不同层次迷宫”,简言之,“上下”就是通过楼梯上下楼,因此更像魔塔游戏了。这一句明显提示需要枚举方向。而且每走一步记为一分钟。

3.“迷宫被石头包围”,这提醒我们不能越界,需要对枚举后的坐标进行剪枝。

Input

The input consists of a number of dungeons. Each dungeon description starts with a line containing three integers L, R and C (all limited to 30 in size).
L is the number of levels making up the dungeon.
R and C are the number of rows and columns making up the plan of each level.
Then there will follow L blocks of R lines each containing C characters. Each character describes one cell of the dungeon. A cell full of rock is indicated by a ‘#’ and empty cells are represented by a ‘.’. Your starting position is indicated by ‘S’ and the exit by the letter ‘E’. There’s a single blank line after each level. Input is terminated by three zeroes for L, R and C.

生词 level n.层次

这里除了上次棋盘问题需要注意的点:接受多组数据、初始化之外,还需要注意这里的层次L就相当于高楼的楼层,魔塔包含多个楼层,每个楼层可以视作一个二维图。为了更为准确地表述主角的位置,不妨用层次、横坐标、纵坐标来表述,这里要用结构体存储来对应唯一的位置。是的,这也就是题目中“3D迷宫”的3D的含义。

因此我们不妨得出位置结构体、标记数组、方向数组、起点和终点的定义

struct node{
	int m,x,y,s;
};
int s[3],e[3],book[35][35][35],next[6][3]={{0,0,1},{0,1,0},{0,0,-1},{0,-1,0},{1,0,0},{-1,0,0}};

对于每组魔塔的接受,需要按照魔塔拥有的层次L来获取不同层的地图。由于地图是用字符表示石头与平地,所以用二位数组接受每层地图,但是为了和位置的表述对应,地图列为三维数组(层次、横坐标、纵坐标)。

char map[35][35][35];
while(cin>>l>>r>>c&&l){
	for(k=1;k<=l;k++)
		for(i=1;i<=r;i++)
			for(j=1;j<=c;j++)
			cin>>map[k][i][j];
	memset(book,0,sizeof(book));
}

Output

Each maze generates one line of output. If it is possible to reach the exit, print a line of the form

Escaped in x minute(s).

where x is replaced by the shortest time it takes to escape.If it is not possible to escape, print the line

Trapped!

求解最短路,无疑是要用BFS。(DFS也可以求解,不过导致报错“Time Limit Exceeded”,因为它不是最短路的最优解法)

这里的搜索思路对应《啊哈算法》中的第四章第三节《层层递进——广度优先搜索》,所以仅做一些本题和该书上题不同之处和典型遗漏点的提醒。

1.任意元素入队后都要标记走过

que.push(t);
book[t.m][t.x][t.y]=1;

2.STL中的入队是将变量的内容录入队列的新元素,而不是录入变量的地址,因此可以利用临时变量形成新位置,如果能走则可以入队。

3.队首和临时位置需要各自使用结构体来接受信息。

temp=que.front();
book[tm][tx][ty]=1;
					p.m=tm;
					p.x=tx;
					p.y=ty;
					p.s=ts;
					que.push(p);

4.由于加入了层次,需要对层次是否越界进行判断,这部分放在越界判断之中

if(tm<1||tm>l||tx<1||tx>r||ty<1||ty>c)
				continue;

5.判断是否可走

可走情况分为两种字符“.”、“E”,可以**直接用非’#’**石头表达。

map[tm][tx][ty]!='#'

6.判断是否到达终点

由于耗时需要利用队首元素,所以可以利用队首元素的耗时获取要输出的耗时。考虑到到达终点属于试探结果,因此放在试探为可以走的程序段部分判断是否为终点。

为了继续接受下一组内容,需要结束BFS,而不是结束程序,用flag标记来标识已经找到终点来结束BFS的部分。

if(map[tm][tx][ty]!='#'&&!book[tm][tx][ty]){
					book[tm][tx][ty]=1;
					p.m=tm;
					p.x=tx;
					p.y=ty;
					p.s=ts;
					que.push(p);
					if(map[tm][tx][ty]=='E')
					{	
						flag=1;
						break;
					}
				}


综上,代码为

#include<queue>
#include<cstring>
#include<iostream>
using namespace std;
int l,r,c;
char map[35][35][35];
int s[3],e[3],book[35][35][35],next[6][3]={{0,0,1},{0,1,0},{0,0,-1},{0,-1,0},{1,0,0},{-1,0,0}};
struct node{
	int m,x,y,s;
};
struct node t,temp,p;
int main(){
	int i,j,k,tm,tx,ty,ts,flag=0;
	freopen("test.txt","r",stdin); 
	while(cin>>l>>r>>c&&l){
		for(k=1;k<=l;k++)
			for(i=1;i<=r;i++)
				for(j=1;j<=c;j++)
				{cin>>map[k][i][j];
				if(map[k][i][j]=='S')
					{
					s[0]=k;
					s[1]=i;
					s[2]=j;
					}
					else if(map[k][i][j]=='E')
					{
					e[0]=k;
					e[1]=i;
					e[2]=j;
					}
				}
		memset(book,0,sizeof(book));
		queue<node> que;
		t.m=s[0];
		t.x=s[1];
		t.y=s[2];
		t.s=0;
		que.push(t);
		book[t.m][t.x][t.y]=1;
		flag=0;
		while(!que.empty()){
			temp=que.front();
			for(i=0;i<6;i++)
			{
				tm=temp.m+next[i][0];
				tx=temp.x+next[i][1];
				ty=temp.y+next[i][2];
				ts=temp.s+1;
				if(tm<1||tm>l||tx<1||tx>r||ty<1||ty>c)
				continue;
				if(map[tm][tx][ty]!='#'&&!book[tm][tx][ty]){
					book[tm][tx][ty]=1;
					p.m=tm;
					p.x=tx;
					p.y=ty;
					p.s=ts;
					que.push(p);
					if(map[tm][tx][ty]=='E')
					{	
						flag=1;
						break;
					}
				}
			}
			if(flag)break;
			que.pop();
		}
		if(flag)
			cout<<"Escaped in "<<que.back().s<<" minute(s)."<<endl;
		else
		cout<<"Trapped!"<<endl;
	} 
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值