OJ-P1950【流星雨】

描述 Description
   贝茜听说了一个骇人听闻的消息:一场流星雨即将袭击整个农场,由于流星
体积过大,它们无法在撞击到地面前燃烧殆尽,届时将会对它撞到的一切东西
造成毁灭性的打击。很自然地,贝茜开始担心自己的安全问题。以FJ牧场中最
聪明的奶牛的名誉起誓,她一定要在被流星砸到前,到达一个安全的地方(也就
是说,一块不会被任何流星砸到的土地)。如果将牧场放入一个直角坐标系中,
贝茜现在的位置是原点,并且,贝茜不能踏上一块被流星砸过的土地。

  根据预报,一共有M颗流星(1 <= M <= 50,000)会坠落在农场上,其中第i颗
流星会在时刻T_i (0 <= T_i <= 1,000)砸在坐标为(X_i, Y_i) 
(0 <= X_i <= 300;0 <= Y_i <= 300)的格子里。流星的力量会将它所在的格子
,以及周围4个相邻的格子都化为焦土,当然贝茜也无法再在这些格子上行走。

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

  请你计算一下,贝茜最少需要多少时间才能到达一个安全的格子。

输入格式 Input Format
 * 第1行: 1个正整数:M

* 第2..M+1行: 第i+1行为3个用空格隔开的整数:X_i,Y_i,以及T_i

输出格式 Output Format
 第1行: 输出1个整数,即贝茜逃生所花的最少时间。如果贝茜无论如何都无法
     在流星雨中存活下来,输出-1

一道比较逻辑性的BFS,看对思路的严谨程度了。。
有一个比较隐晦的坑:流星落地点的范围小于人可以行走的范围。
Code+注释:

#include<iostream>
#include<iomanip>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
using namespace std;
int M,Q[90086][3],Smap[320][320];//Q为队列数组,Smap为地图矩阵
int xx[5]={0,-1,1,0,0},yy[5]={0,0,0,-1,1};
struct da
{
int xi,yi,ti;
}map[50086];//记录流星的落点及时间
void init()
{
cin>>M;
for(int i=1;i<=M;i++)
scanf("%d%d%d",&map[i].xi,&map[i].yi,&map[i].ti);
}
bool mycmp(da a,da b)
{return a.ti<b.ti;}//让流星按落地时间升序排列
int main()
{
init();
sort(map+1,map+M+1,mycmp);
memset(Smap,0,sizeof(Smap));
memset(Q,-1,sizeof(Q));
Q[1][1]=0,Q[1][2]=0; 

int FSpoint=1,Ttime=0,head=1,tail=2;

while(map[FSpoint].ti==Ttime)//模拟当前时刻Ttime流星砸落过程
{
Smap[map[FSpoint].xi][map[FSpoint].yi]=-1;
for(int i=1;i<=4;i++)
if(map[FSpoint].xi+xx[i]>=0&&map[FSpoint].xi+xx[i]<=300)
if(map[FSpoint].yi+yy[i]>=0&&map[FSpoint].yi+yy[i]<=300)
Smap[map[FSpoint].xi+xx[i]][map[FSpoint].yi+yy[i]]=-1;
FSpoint++;
}
Ttime=1;
while(Ttime<=map[M].ti)//按时间每过1个单位循环
{
while(map[FSpoint].ti==Ttime)//模拟当前时刻Ttime流星砸落过程
{
Smap[map[FSpoint].xi][map[FSpoint].yi]=-1;
for(int i=1;i<=4;i++)
if(map[FSpoint].xi+xx[i]>=0&&map[FSpoint].xi+xx[i]<=300)
if(map[FSpoint].yi+yy[i]>=0&&map[FSpoint].yi+yy[i]<=300)
Smap[map[FSpoint].xi+xx[i]][map[FSpoint].yi+yy[i]]=-1;
FSpoint++;

}

//从上一层可以行走的点拓展出本次的时间点人可以走到的位置
int ansnow=tail;
for(int i=head;i<tail;i++)
{
for(int j=1;j<=4;j++)
if(Q[i][1]+xx[j]>=0&&Q[i][1]+xx[j]<=310)
if(Q[i][2]+yy[j]>=0&&Q[i][2]+yy[j]<=310)
if(Smap[Q[i][1]+xx[j]][Q[i][2]+yy[j]]==0&&(Q[i][1]+xx[j]!=0||Q[i][2]+yy[j]!=0))
{
Q[ansnow][1]=Q[i][1]+xx[j];
Q[ansnow++][2]=Q[i][2]+yy[j];
Smap[Q[i][1]+xx[j]][Q[i][2]+yy[j]]=Ttime;
}

}head=tail;tail=ansnow;
Ttime++;//时间+1,队头与队尾向后“一层”
}

//==================找逃生时间最小值并判断是否输出-1==========
if(Smap[0][0]==0)
{cout<<0<<endl;return 0;}

int anss=21478953,qqqqq=0;
for(int i=0;i<=310;i++)
for(int j=0;j<=310;j++)
if(Smap[i][j]!=-1&&Smap[i][j]!=0)
anss=min(anss,Smap[i][j]),qqqqq=1;
if(!qqqqq) cout<<-1<<endl;
else cout<<anss<<endl;
return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值