22. 地下城与勇士

目录

题目

思路

注意事项

C++完整代码(含详细注释)


题目

Description
龙神觉得无聊于是来到了地下城,这里是一个巨大的迷宫,有一些可以通行的路、一些不可以通行的墙,还有一些怪物。虽然龙神可以轻易地干掉这些怪物,但他觉得这样就太没意思了,他观察到这些怪物每  秒会消失一次(例如  时,则第  秒怪物是消失的),每一秒龙神可以选择向上下左右行走一步(不能在原地不动)。龙神想知道在避开全部怪物的条件下,到达出口所需要的最短时间。
Input
第一行输入一个整数 ,代表用例组数。
每组用例的第一行包括三个整数  和 , 分别表示地下城迷宫的行数、列数、怪物的消失间隔。
接下来的  行代表迷宫,.表示可以通行的路,#表示墙,*表示怪物,S表示起点,E代表出口。
Output
输出一个整数,表示龙神走出地下城迷宫的最短时间,如果龙神不能走出迷宫则输出-1。
Source
BITACM2018第一轮积分赛(三)- Problem J
 


思路

  1. 使用BFS算法来搜索从起点到出口的最短路径。
  2. 遍历四个方向来扩展节点,并使用队列来存储待扩展的节点。
  3. 使用一个三维向量visited来记录已访问的单元格,以避免重复访问。
  4. 在计算下一个单元格的坐标和步数时,使用取模运算符来实现怪物消失的间隔效果。
  5. 使用INT_MAX来表示最小步数的初始值,如果最小步数仍然是INT_MAX,则表示未找到最短路径。

注意事项

  1. 在遍历四个方向时,使用一个二维数组dir来表示四个方向的偏移量。
  2. 在计算下一个单元格的坐标和步数时,需要注意边界条件,避免越界。
  3. 需要判断下一个单元格是否是墙,如果是墙则不能通过,需要跳过。
  4. 在判断下一个单元格是否是怪物时,需要考虑当前步骤是否是k的倍数,如果不是则不能通过,需要跳过。
  5. 需要标记已访问的单元格,以避免重复访问,可以使用visited数组来记录已访问的单元格。
  6. 如果最小步数ans仍然是INT_MAX,则表示未找到最短路径,输出-1。
  7. 在读取迷宫地图时,需要注意迷宫的行数和列数的范围。
  8. 在找到出口后,可以及时跳出循环,提高效率。
  9. 可以使用队列来实现BFS算法,将待扩展的节点压入队列,然后从队列中弹出节点进行扩展。

 

C++完整代码(含详细注释)

提交乐学的话记得改一改呀,查重!!!

#include <iostream>
#include <queue>
#include <vector>
#include <climits>
using namespace std;
//定义一个名为node的结构体。
// 三个成员变量:x、y和step。分别表示节点的x坐标、y坐标和步数。
struct node {
	int x, y, step;
	node(int _x = 0, int _y = 0, int _step = 0) {//初始化结构体的成员变量
		x = _x;
		y = _y;
		step = _step;
	}
};

int main() {
	int T;
	cin >> T;
	int dir[4][2] = { 0, 1, 1, 0, -1, 0, 0, -1 }; // 表示四个方向
	while (T--) {
		int n, m, k, Sx, Sy;
		cin >> n >> m >> k;
		vector<vector<char>> map(n, vector<char>(m)); // 用于存储迷宫地图
		vector<vector<vector<bool>>> visited(n, vector<vector<bool>>(m, vector<bool>(k, 0))); // 用于记录已访问的单元格
		queue<node> que; // 用于执行BFS的队列

		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				cin >> map[i][j]; // 读取迷宫地图
				if (map[i][j] == 'S') {
					Sx = i;
					Sy = j;
				}
			}
		}

		int ans = INT_MAX; // 用于存储到达出口所需的最小步数,默认为INT_MAX
		que.push(node(Sx, Sy, 0)); // 将起点节点压入队列
		visited[Sx][Sy][0] = 1; // 标记起点为已访问

		while (!que.empty()) {
			node tmp = que.front(); que.pop(); // 从队列中弹出前端节点
			if (map[tmp.x][tmp.y] == 'E') { // 如果当前节点是出口
				ans = tmp.step; // 更新最小步数
				break; // 跳出循环
			}
			for (int i = 0; i < 4; i++) { // 遍历四个方向
				int x = tmp.x + dir[i][0], y = tmp.y + dir[i][1], stp = tmp.step + 1; // 计算下一个单元格的坐标和步数
				if (x<0 || x>n - 1 || y<0 || y>m - 1 || map[x][y] == '#' || visited[x][y][stp % k]) continue; // 检查下一个单元格是否越界、是墙,或者已在同一步骤中被访问过
				if (map[x][y] == '*' && (stp % k)) continue; // 如果下一个单元格是怪物,且当前步骤不是k的倍数,则跳过

				que.push(node(x, y, stp)); // 将下一个节点压入队列
				visited[x][y][stp % k] = 1; // 标记下一个节点为已访问
			}
		}
		if (ans == INT_MAX) cout << -1 << endl; // 如果最小步数仍然是INT_MAX,表示未到达出口,输出-1
		else cout << ans << endl; // 否则输出最小步数
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

榆榆欸

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

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

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

打赏作者

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

抵扣说明:

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

余额充值