【第二十二题】地下城与勇士(北理工/北京理工大学/程序设计方法与实践/小学期 )

目录

Description

思路

代码

我的版本


Description

龙神觉得无聊于是来到了地下城,这里是一个巨大的迷宫,有一些可以通行的路、一些不可以通行的墙,还有一些怪物。虽然龙神可以轻易地干掉这些怪物,但他觉得这样就太没意思了,他观察到这些怪物每 k 秒会消失一次(例如 k 等於 3 时,则第 3 逗號 空格 6 逗號 空格 9 逗號 空格 中线省略号 秒怪物是消失的),每一秒龙神可以选择向上下左右行走一步(不能在原地不动)。龙神想知道在避开全部怪物的条件下,到达出口所需要的最短时间。

 Input 第一行输入一个整数 T 空格 左括号 1 小於等於 T 小於等於 10 右括号,代表用例组数。  每组用例的第一行包括三个整数 n 逗號 空格 m 空格 左括号 1 小於等於 n 逗號 空格 m 小於等於 100 右括号 和 ,k 空格 左括号 1 小於等於 k 小於等於 50 右括号 分别表示地下城迷宫的行数、列数、怪物的消失间隔。  接下来的 n 行代表迷宫,.表示可以通行的路,#表示墙,*表示怪物,S表示起点,E代表出口。  

Output 输出一个整数,表示龙神走出地下城迷宫的最短时间,如果龙神不能走出迷宫则输出-1。  

Source BITACM2018第一轮积分赛(三)- Problem J

思路

这道题,仍然是bfs。

但是和上一道不一样了。

你可以上csdn搜bfs迷宫例题,最基本的都是走迷宫:一张图,一些墙,一个起点,一个终点,最短路径。这种题的简单之处在于这个迷宫本身已经是图了,所以只需要bfs即可

这种迷宫目前我见过三种变式:

  1. 21题这种,没有给你图,需要自己用map<int,vector<int>>去构造
  2. 22题这种,给了现成的图,但是有怪,而且也不是最短路径,而是最短时间
  3. 还有一种,要你输出最短路径

这题大体思路不难,就是走迷宫嘛,不计时间,套csdn的模板即可。 

关键就是理解一下为什么要开三维的vis数组,假设我的第三维一直更新,那么怎么重复都不会触发已经访问标记,直到我走过一个k周期,就有可能触发了。

其实理论上不考虑时间的话是不用开vis的,因为在怪的作用下,我们是可以回头的(这个时候已经不是最短步数的迷宫问题了)
之所以要开vis,是为了减少无谓的回头,但是又出来一个新的问题:第三维开多大?
为了解决上限不明的问题,就使用了%来限制范围,节省空间
%的合理性:在时间time和时间time+k访问同一个位置是完全等价的!
然而time和time+k这两个时间点的怪是完全一样的,
也就是说,在周期上,反而没有怪的影响了,也就是说在这一步走就是彻底没有意义的了,故跳过

代码

原题,J

BITACM2018第一轮积分赛(三)题解_终有绿洲摇曳在沙漠-CSDN博客A. 很会dp 出题人: zhber AC/TOT: 1/50题解: 因为 V&quot; role=&quot;presentation&quot; style=&quot;position: relative;&quot;&gt;VVV 实在太大了,所以做背包 dp&quot; role=&quot;presentation&quot; style=&quot;position: relative;&ahttps://blog.csdn.net/dragon60066/article/details/79212465

我的版本

#include<cstdio>
#include<cstring>
#include<queue>
#define SIZE 101
const int dir[2][4] = { {1,0,0,-1},
						{0,1,-1,0} };
char maze[SIZE][SIZE];
bool vis[SIZE][SIZE][51];
struct point {
	int x;
	int y;
	int time;
	//point(int tx, int ty, int ttime)//定义一个构造函数快速录入
	//{
	//	x = tx;
	//	y = ty;
	//	time = ttime;
	//}
};
int main(void)
{
	freopen("input.txt", "r", stdin);
	int T;
	scanf("%d", &T);
	while (T--)
	{
		//对每个地图进行操作
		//初始化
		point start, now, next, end;
		int n, m, k, ch;
		int ans = -1;
		std::queue <point> q;
		memset(vis, false, sizeof(vis));
		//读入图
		scanf("%d %d %d\n", &n, &m, &k);//注意吸收换行
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				ch = getchar();
				maze[i][j] = ch;
				if (ch == 'S')//记录起点
				{
					start.x = i;
					start.y = j;
					start.time = 0;
				}
				if (ch == 'E')
				{
					end.x = i;
					end.y = j;
				}
			}
			getchar();//每一行都有换行符
		}
		//bfs
		q.push(start);
		vis[start.x][start.y][start.time % k] = true;
		while (!q.empty())
		{
			//取出
			now = q.front();
			q.pop();
			if (now.x == end.x && now.y == end.y)
			{
				ans = now.time;
				break;
			}
			//放入下一步
			for (int i = 0; i < 4; i++)
			{
				next.x = now.x + dir[0][i];
				next.y = now.y + dir[1][i];
				next.time = now.time + 1;
				//注意判断边界,墙,重复访问,怪
				if (next.x<1 || next.x>n || next.y > m || next.y < 1
					|| maze[next.x][next.y] == '#'
					|| vis[next.x][next.y][next.time % k]
					|| (maze[next.x][next.y] == '*' && next.time % k != 0))//这块为了可读性写了!=0,其实不写也可以
				{
					continue;
				}
				q.push(next);
				vis[next.x][next.y][next.time % k] = true;
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亦梦亦醒乐逍遥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值