Meteor Shower

Meteor Shower

Bessie听说一场非凡的流星雨即将来临; 据报道,这些流星将坠入地球并摧毁他们击中的任何东西。为了安全起见,她发誓要找到一个安全的地方(一个永远不被流星摧毁的地方)。她目前正在坐标平面的原点放牧,并希望搬到一个新的,更安全的地方,同时避免被沿途的流星摧毁。

据报告说,M颗流星(1≤ M ≤50000)将会坠入,流星i将在时间Ti(0 ≤ Ti ≤1,000)撞击点(Xi, Yi) (0 ≤ Xi ≤ 300; 0 ≤ Yi ≤ 300) 。每颗流星都会破坏它所撞击的点以及四个直线相邻的格点。

Bessie在时间0离开原点并且可以在第一象限中以每秒一个距离单位的速率平行于轴方向行进到达尚未被流星破坏的任何(通常是4个)相邻直线点。她到达一个点的时间不能大于或等于该点被摧毁的时间点。

确定Bessie到达安全地点所需的最短时间。

Input

第1行:单个整数:M
第2行~M +1行:第i + 1行包含三个以空格分隔的整数:Xi, Yi, and Ti

Output

第1行:Bessie到达安全地点所需的最短时间,如果不可能,则为-1。

Sample Input

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

Sample Output

5

C++编写:

这道题的相邻直线点可能有点难以理解,此处简单地解释一下,假如在某一时刻一颗流星撞击点(3,3),那么该时间点被摧毁的地方有五个——(3,3)、(3,2)、(3,4)、(2,3)、(4,3),其他的应该没有什么难理解的了,下面是代码:

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;

const int INF=0x3f3f3f3f;
const int MAX_M=50010;
const int MAX_N=310;

int map[MAX_N][MAX_N];
int d[MAX_N][MAX_N];
int dx[5]={1,0,-1,0,0},dy[5]={0,1,0,-1,0};
int m,x,y,t;  

typedef pair<int,int> P;

struct Meteor {
	int x;
	int y;
	int t;
} meteors[MAX_M];

bool compare (Meteor a, Meteor b) 
{
	if (a.t < b.t)   return true;
	else   return false;
}

bool check(int x,int y)
{
    if(x>=0 && x<MAX_N && y>=0 && y<MAX_N)   return true;
    else  return false;
}

int bfs()
{
    queue<P> que;
    if(map[0][0] == 0)    return -1;
    else if(map[0][0] == INF)     return 0;
    que.push(P(0,0));
    
    while(que.size())
    {
        P p=que.front();
        que.pop();
        int px=p.first,py=p.second;
        if (px >= MAX_N || py >= MAX_N)  continue;      //这句话仅用于一种保护措施,基本不可能执行这行代码
        
        for(int i=0;i<4;i++)
        {
            int nx=px+dx[i],ny=py+dy[i];
            if(check(nx,ny))
            {
                if(map[nx][ny] == INF)      //该点永远不会被摧毁
                {
                    return ++d[px][py];
                }
                if(d[px][py]+1 < map[nx][ny] && !d[nx][ny])    //在该点被摧毁之前到达并且这个点还没有被走过
                {                                              //这里有点绕,这个点被走过了之后就不能再回来了吗
					que.push(P(nx, ny));                       //这个点早晚要被摧毁,同时我们要求的是最短时间
					d[nx][ny] = d[px][py] + 1;                 //再走一次其实是耽搁一次时间,故没有必要再走
				}                                              
            }
        }
    }
    return -1;
}

void solve()
{
    for(int i=0;i<MAX_N;i++)
    {
        for(int j=0;j<MAX_N;j++)
        {
            map[i][j]=INF;      //初始化数组
        }
    }
    for(int i=0;i<m;i++)
        cin>>meteors[i].x>>meteors[i].y>>meteors[i].t;
    sort(meteors, meteors + m, compare);                //按t从小到大排列
    for(int i=0;i<m;i++)
    {
        for(int j=0;j<5;j++)
        {
            int nx=meteors[i].x,ny=meteors[i].y;
            nx += dx[j];
            ny += dy[j];
            if(check(nx,ny) && map[nx][ny]>meteors[i].t)       //记录一个点被摧毁的最早时间
                map[nx][ny] = meteors[i].t;
        }
    } 
    cout<<bfs()<<endl;
}

int main()
{
    ios::sync_with_stdio(false);
    while(cin>>m)
        solve();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值