2512: 【普及/提高-】【P2895】Meteor Shower S

内存限制:128 MB 时间限制:1.000 S
评测方式:文本比较 命题人:
提交:7 解决:5

题目描述

贝茜听说一场特别的流星雨即将到来:这些流星会撞向地球,并摧毁它们所撞击的任何东西。她为自己的安全感到焦虑,发誓要找到一个安全的地方(一个永远不会被流星摧毁的地方)。

如果将牧场放入一个直角坐标系中,贝茜现在的位置是原点,并且,贝茜不能踏上一块被流星砸过的土地。

根据预报,一共有 lns="http://www.w3.org/1998/Math/MathML"> 颗流星 lns="http://www.w3.org/1998/Math/MathML">(150,000) 会坠落在农场上,其中第 lns="http://www.w3.org/1998/Math/MathML"> 颗流星会在时刻 lns="http://www.w3.org/1998/Math/MathML"> (0<=Ti<=1000)砸在坐标为 lns="http://www.w3.org/1998/Math/MathML">(,)(0300lns="http://www.w3.org/1998/Math/MathML">0300) 的格子里。流星的力量会将它所在的格子,以及周围 lns="http://www.w3.org/1998/Math/MathML">4 个相邻的格子都化为焦土,当然贝茜也无法再在这些格子上行走。

贝茜在时刻 lns="http://www.w3.org/1998/Math/MathML">0 开始行动,它只能在第一象限中,平行于坐标轴行动,每 lns="http://www.w3.org/1998/Math/MathML">1 个时刻中,她能移动到相邻的(一般是 lns="http://www.w3.org/1998/Math/MathML">4 个)格子中的任意一个,当然目标格子要没有被烧焦才行。如果一个格子在时刻 lns="http://www.w3.org/1998/Math/MathML"> 被流星撞击或烧焦,那么贝茜只能在 lns="http://www.w3.org/1998/Math/MathML"> 之前的时刻在这个格子里出现。 贝西一开始在 lns="http://www.w3.org/1998/Math/MathML">(0,0)

请你计算一下,贝茜最少需要多少时间才能到达一个安全的格子。如果不可能到达输出 lns="http://www.w3.org/1998/Math/MathML">1

输入

共 lns="http://www.w3.org/1998/Math/MathML">+1 行,第 lns="http://www.w3.org/1998/Math/MathML">1 行输入一个整数 lns="http://www.w3.org/1998/Math/MathML">,接下来的 lns="http://www.w3.org/1998/Math/MathML"> 行每行输入三个整数分别为 lns="http://www.w3.org/1998/Math/MathML">,,

输出

贝西到达安全地点所需的最短时间,如果不可能,则为 lns="http://www.w3.org/1998/Math/MathML">1

样例输入 复制

4
0 0 2
2 1 2
1 1 2
0 3 5

样例输出 复制

5

提示

#include<bits/stdc++.h>
using namespace std;
#define maxn 310
struct coord {
	int x,y;
};
queue<coord> Q;
int ans[maxn][maxn],death[maxn][maxn]; //death表示该点被流星雨 砸中的时间
int wk[4][2]={{0,1},{1,0},{-1,0},{0,-1}}; 
int main(){
    int m,Ans=100000;
    memset(ans,-1,sizeof(ans));  //全部赋值为-1
	memset(death,0x7f,sizeof(death));  //全部赋值为一个很大的值,大约2e10
	cin>>m;
	for (int i=1;i<=m;i++) {
		int x,y,t;
		cin>>x>>y>>t;
#define MIN(x,y,t) if (x>=0&&y>=0) death[x][y]=min(death[x][y],t)
        MIN(x,y,t);
        for (int k=0;k<4;k++)
            MIN(x+wk[k][0],y+wk[k][1],t);
        //记录下流星和上下左右影响范围烧焦的时间 
	} 
	Q.push(coord{0,0});  //原点加入到队列
	ans[0][0]=0;
	while(!Q.empty()) {
		coord u=Q.front();  //取出队首
		int ux=u.x,uy=u.y;
		Q.pop();
		for (int k=0;k<4;k++) {  //奶牛向4个方向运动
		    int x=ux+wk[k][0],y=uy+wk[k][1];
			if (x<0||y<0||ans[x][y]!=-1||ans[ux][uy]+1>=death[x][y])
			    continue;  /*当目标格子的最早到达时间已经比被破坏时间晚时不能更新*/ 
		    ans[x][y]=ans[ux][uy]+1;
		    Q.push((coord){x,y});  //扩展的结点加入队列 
		} 
	}
	for (int i=0;i<=305;i++)
	    for (int j=0;j<=305;j++)
		    if (death[i][j]>1000&&ans[i][j]!=-1)
			    Ans=min(Ans,ans[i][j]);  /*统计答案,在所有安全区域且能达到的点中找到达最早的*/ 
	if (Ans==100000)
	    puts("-1");
	else
	    printf("%d",Ans);	
	return 0;
}

#include<bits/stdc++.h>
using namespace std;
struct point {
	int x, y, t, step, visit;
}ps[1005][1005];
int main(){
    int m, x, y, t, tx, ty, dx[5] = {-1,1,0,0,0}, dy[5] = {0,0,-1,1,0};
    cin >> m;
    memset(ps,-1,sizeof(ps));
    for(int i = 0; i < 1000; i++) {
    	for(int j = 0; j < 1000; j++) {
    		ps[i][j].x = i;
    		ps[i][j].y = j;
		}
	}
	for(int i = 0; i < m; i++) {
		cin >> x >> y >> t;
		for (int j = 0; j < 5; j++) {
			tx = x + dx[j];
			ty = y + dy[j];
			if (tx < 0 || ty < 0) continue;
			if (ps[tx][ty].t == -1 || ps[tx][ty].t > t ) ps[tx][ty].t = t;
		}
	}
	queue<point> q;
	ps[0][0].visit = 1;
	ps[0][0].step = 0;
	q.push(ps[0][0]);
	while (!q.empty()) {
		point p=q.front();
		q.pop();
		for (int i = 0; i < 4; i++) {
			tx=p.x + dx[i];
			ty=p.y + dy[i];
			if (tx < 0 || ty < 0 || ps[tx][ty].visit == 1) continue;
			if (ps[tx][ty].t == -1) {
				cout << p.step + 1;
				return 0;
			}
		    if (p.step + 1 < ps[tx][ty].t) {
		        ps[tx][ty].visit = 1;
		        ps[tx][ty].step = p.step + 1;
		        q.push(ps[tx][ty]);			
		    }
	    }
	}
	cout << -1;
	return 0;
}