解题报告:洛谷P2895 [USACO08FEB]流星雨Meteor Shower

前言

  • 先吐槽一波翻译…

牛去看流星雨,不料流星掉下来会砸毁上下左右中五个点。每个流星掉下的位置和时间都不同,求牛能否活命,如果能活命,最短的逃跑时间是多少?


题目描述

Bessie听说有一场壮丽的流星雨即将来临,而且据说陨石将要落下来撞击地球并摧毁一切它遇到的东西。为了保证自己的安全,bessie决定到一个安全的(永远不会被陨石击毁)地方去。

报道表明将有M颗陨石落下(1 ≤ M ≤ 50,000),第i个陨石将在Ti(0 ≤ Ti ≤ 1,000)时刻砸中(Xi,Yi)点(0 ≤ Xi ≤ 300; 0 ≤ Yi ≤ 300) 。每颗陨石将击毁它直接砸中的点以及四个与其直接相邻的点

她现在所处的地方是坐标系的原点,并从零时刻起出发,前往一个安全的地点,要求是她经过某点时该点未被击毁。她只能在坐标系的第一象限以及x,y轴的正半轴上活动。

求她能到达一个安全地点的最短时间。

输入输出格式

第一行:陨石个数M。

第二行至第M+1行:第i+1行有三个整数表示:Xi,Yi,和Ti。

输出只有一行,即Bessie所需的最短时间。如果她永远无法到达一个安全的地方,输出-1。


代码

#include 
using namespace std;

const int MAXN = 305;

struct node
{
	int x,y,t;
}S,cur,nxt;

int m,xi,yi,ti;
int tim[MAXN][MAXN],vis[MAXN][MAXN],dx[] = {-1,1,0,0},dy[] = {0,0,-1,1};
queue<node> Q;

inline void explode(int x,int y,int t)
{
	if (tim[x][y]) tim[x][y] = min(tim[x][y],t);
	else tim[x][y] = t;
	for (int i = 0;i < 4;i++)
	{
		int nx = x + dx[i];
		int ny = y + dy[i];
		if (nx < 0 || ny < 0) continue;
		if (tim[nx][ny]) tim[nx][ny] = min(tim[nx][ny],t);
		else tim[nx][ny] = t;
	}
}

void init()
{
	scanf("%d",&m);
	for (int i = 1;i <= m;i++)
	{
		scanf("%d%d%d",&xi,&yi,&ti);
		if (!ti) ti = -1;
		explode(xi,yi,ti);
	}
}

void bfs()
{
	if (!tim[0][0]) {printf("0"); exit(0);}
	Q.push(S);
	vis[S.x][S.y] = true;
	while (!Q.empty())
	{
		cur = Q.front();
		Q.pop();
		for (int i = 0;i < 4;i++)
		{
			int nx = cur.x + dx[i];
			int ny = cur.y + dy[i];
			if (nx < 0 || ny < 0 || vis[nx][ny] || (tim[nx][ny] <= cur.t + 1 && tim[nx][ny])) continue;
			nxt.x = nx;
			nxt.y = ny;
			nxt.t = cur.t + 1;
			if (!tim[nxt.x][nxt.y])
			{
				printf("%d",nxt.t);
				exit(0);
			}
			vis[nxt.x][nxt.y] = true;
			Q.push(nxt);
		}
	}
	printf("-1");
}

int main()
{
	init();
	bfs();
	return 0;
}

分析

  • 个人感觉目前做过的题中,离线处理总归比在线处理简单…所以这题先把炸弹爆炸的结果计算出来再BFS。走到一个没有被计算过爆炸时间的点就安全了。
  • 显然同一位置爆炸时间有不同时取较小值。
	if (tim[x][y]) tim[x][y] = min(tim[x][y],t);
	else tim[x][y] = t;
	...
	if (tim[nx][ny]) tim[nx][ny] = min(tim[nx][ny],t);
	else tim[nx][ny] = t;

注意

  • 考虑0时刻就爆炸的炸弹。怎么处理呢?作者是把他设为-1。
    if (!ti) ti = -1;
  • 假如原点已经安全呢?洛谷的测试点没有考虑这一点。但假如有以下数据的话,应该输出0,但AC代码输出-1:
1
1 1 0
  • 注意0是不能用来比较的,0代表安全不代表爆炸时间,若有炸弹爆炸应该直接赋值。
if (tim[nx][ny]) ...

你可能感兴趣的:(解题报告)