题目描述
贝茜听说了一个骇人听闻的消息:一场流星雨即将袭击整个农场,由于流星体积过大,它们无法在撞击到地面前燃烧殆尽,届时将会对它撞到的一切东西造成毁灭性的打击。很自然地,贝茜开始担心自己的安全问题。
以 Farmer John 牧场中最聪明的奶牛的名誉起誓,她一定要在被流星砸到前,到达一个安全的地方(也就是说,一块不会被任何流星砸到的土地)。
如果将牧场放入一个直角坐标系中,贝茜现在的位置是原点,并且,贝茜不能踏上一块被流星砸过的土地。
根据预报,一共有 M M M 颗流星 ( 1 ≤ M ≤ 50 , 000 ) (1≤M≤50,000) (1≤M≤50,000) 会坠落在农场上,其中第 i i i颗流星会在时刻 T i T_i Ti ( 0 ≤ T i ≤ 1 , 000 ) (0\leq T_i\leq1,000) (0≤Ti≤1,000)砸在坐标为 ( X i , Y i ) (X_i, Y_i) (Xi,Yi) ( 0 ≤ X i ≤ 300 , 0 ≤ Y i ≤ 300 ) (0\leq X_i\leq 300,0\leq Y_i\leq300) (0≤Xi≤300,0≤Yi≤300)的格子里。
流星的力量会将它所在的格子,以及周围 4 4 4 个相邻的格子都化为焦土,当然贝茜也无法再在这些格子上行走。
贝茜在时刻 0 0 0 开始行动,它只能在第一象限中,平行于坐标轴行动,每 1 1 1 个时刻中,她能移动到相邻的(一般是 4 4 4 个)格子中的任意一个,当然目标格子要没有被烧焦才行。如果一个格子在时刻 t t t 被流星撞击或烧焦,那么贝茜只能在 t t t 之前的时刻在这个格子里出现。 贝西一开始在 ( 0 , 0 ) (0,0) (0,0)。
请你计算一下,贝茜最少需要多少时间才能到达一个安全的格子。如果不可能到达输出 − 1 -1 −1。
输入格式
第
1
1
1行
1
1
1个整数
M
M
M。
第
2
2
2到第
M
+
1
M+1
M+1行,每行3个整数,分别为
X
i
X_i
Xi,
Y
i
Y_i
Yi,
T
i
T_i
Ti,用空格分隔。
输出格式
一个整数 t t t,表示贝茜最少需要多少时间才能到达一个安全的格子。如果不可能到达输出 − 1 -1 −1
输入样例
4
0 0 2
2 1 2
1 1 2
0 3 5
输出样例
5
算法思想(BFS)
这是一个与时间赛跑的游戏,需要计算的是贝茜最少需要多少时间才能到达一个安全的格子。
根据输入能得到每个格子被流星击中的时间,如果再能计算出贝茜移动到每个格子的最短时间,就能判断出贝茜能否安全地到达该格子,那么贝茜移动到第一个安全(没有被流星击中或者波及到)的格子的时间就是最终答案。
因此可以考虑使用广度优先搜索,记录到达每个格子的最短时间。
算法实现
- 输入每颗流星击中的坐标 ( x , y ) (x, y) (x,y)和时间 t t t,得到 ( x , y ) (x,y) (x,y)以及周围4个格子被陨石击中的最小时刻。
广度优先搜索到达每个格子的短时间:
- 将起点 ( 0 , 0 ) (0,0) (0,0)加入队列
- 只要队列不空:
- 从队列取出一点
- 如果该点是安全的,那么返回到达该点的最短时间
- 否则从该点进行扩展,如果在到达该点之前流星还没有落下,则将该点加入队列,继续搜索
- 搜索结束还没有返回,则意味着无法到达安全格子,返回 − 1 -1 −1。
代码实现
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
const int N = 310, M = 1010, INF = 0x3f3f3f3f;
//mt[x][y]表示陨石集中(x,y)的最小时刻
int mt[N][N];
//dis[x][y]表示走到(x,y)的最短时间
//st[x][y]标记(x,y)是否访问过
int dis[N][N], st[N][N];
int dx[] = {0, -1, 0, 1, 0}, dy[] = {0, 0, 1, 0, -1};
int bfs()
{
int x = 0, y = 0;
queue<PII> q;
dis[x][y] = 0, st[x][y] = 1;
q.push({x, y});
while(q.size())
{
PII t = q.front(); q.pop();
x = t.first, y = t.second;
//该点是安全的
if(mt[x][y] == INF) return dis[x][y];
for(int i = 0; i < 5; i ++)
{
int a = x + dx[i], b = y + dy[i];
if(a < 0 || a >= N || b < 0 || b >= N) continue;
if(st[a][b]) continue;
dis[a][b] = dis[x][y] + 1;
//陨石击中(a,b)时间<=走到(a,b)的时间
if(mt[a][b] <= dis[a][b]) continue;
st[a][b] = 1;
q.push({a, b});
}
}
return -1;
}
int main()
{
int n;
scanf("%d", &n);
//初始化为无穷大
memset(mt, 0x3f, sizeof mt);
for(int i = 0; i < n; i ++)
{
int t, x, y;
scanf("%d%d%d", &x, &y, &t);
for(int j = 0; j < 5; j ++)
{
int a = x + dx[j], b = y + dy[j];
if(a < 0 || a >= N || b < 0 || b >= N) continue;
mt[a][b] = min(mt[a][b], t); //保存陨石撞击的最小时刻
}
}
printf("%d\n", bfs());
}