题解 洛谷 Luogu P2895 [USACO08FEB] Meteor Shower S 广度优先搜索 BFS C++

题目传送门:

P2895 [USACO08FEB] Meteor Shower S - 洛谷 | 计算机科学教育新生态icon-default.png?t=O83Ahttps://www.luogu.com.cn/problem/P2895

思路:

正确处理陨石落下的时间,是 AC 这道题的关键

如果同一个格子有多个陨石砸下来的话,我们显然只要记录最早砸下来时间

用一个数组对陨石落下的时间进行预处理,记录每个格子最早被陨石砸中的时间

接下来就是愉快的 BFS 了。若所处格子为 (x, y),到达该格子的时间为 t[x][y]

试图走向的格子为 (X, Y),其最早被陨石砸中的时间为 g[X][Y]

根据题意,只有当 t[x][y] + 1 < g[X][Y] 时,才能走到这个格子上。+ 1 是走向这个格子花费的时间

代码:

#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef pair<int, int> PII;
const int N = 305;//注意,可能会走到 300 格以外的地方,需要稍微开大一点点
int m, a, b, c, head, tail = -1;
int g[N][N], t[N][N];//g[][] 存对陨石落下时间预处理的结果,t[][] 存走到该格子花费的最短时间
int dx[5] = { -1,1,0,0,0 };//分别为 (x, y) 到它上下左右中格子的坐标变化量
int dy[5] = { 0,0,-1,1,0 };
PII q[N * N];//BFS 队列
bool mk[N][N];//标记数组,走过就不走了。也可以不设这个数组,将 t[][] memset 为全 -1,-1 就表示没走过。多开一个数组感觉更清晰
int BFS()
{
	q[++tail] = { 0,0 };
	mk[0][0] = true;
	while (head <= tail)
	{
		int x = q[head].first, y = q[head].second;
		head++;
		if (g[x][y] == 0x3f3f3f3f) return t[x][y];//走到永远不会被砸的格子,就结束了
		for (int i = 0; i < 4; i++)
		{
			int X = x + dx[i], Y = y + dy[i];
			if (X >= 0 && Y >= 0 && t[x][y] + 1 < g[X][Y] && mk[X][Y] == false)//除了本题最关键的 t[x][y] + 1 < g[X][Y] 以外,都是广搜模板
			{
				q[++tail] = { X,Y };
				mk[X][Y] = true;
				t[X][Y] = t[x][y] + 1;
			}
		}
	}
	return -1;
}
int main()
{
	memset(g, 0x3f, sizeof(g));//先初始化为一个很大的数,如果始终没有被更新,表示没有陨石会砸下到这个格子
	scanf("%d", &m);
	while (m--)
	{
		scanf("%d%d%d", &a, &b, &c);
		for (int i = 0; i < 5; i++)
		{
			int X = a + dx[i], Y = b + dy[i];
			if (X >= 0 && Y >= 0) g[X][Y] = min(g[X][Y], c);
		}
	}
	printf("%d", BFS());
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值