(BFS)Meteor Shower (poj3669)

题目:

Bessie听说有场史无前例的流星雨即将来临;有谶言:陨星将落,徒留灰烬。为保生机,她誓将找寻安全之所(永避星坠之地)。目前她正在平面坐标系的原点放牧,打算在群星断其生路前转移至安全地点。

此次共有M (1 ≤ M ≤ 50,000)颗流星来袭,流星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 - 输出
* 仅一行: Bessie寻得安全点所花费的最短时间,无解则为-1。

Sample Input - 输入样例
4
0 0 2
2 1 2
1 1 2
0 3 5
Sample Output - 输出样例
5

分析与解答:

这里没有给出图,而是通过一些数据让你先建一个图,map[i][j]存的是这个点的爆炸时间,我们初始化最大时间,然后输入数据是把这个数以及他上下左右四个方位全部的时间填上,这里可能会重复爆,我们写最早爆的时间,也就是最小的时间。
然后我们从(0,0)开始搜,bfs中先把(0,0)放入队列,然后只要队列不为空,就继续搜,先取出队首元素。由于如果某个点被炸掉,他就不可能停在该点,最终她停的点一定是没有被炸的那个点,也就是说如果队首元素的map值是我们一开始赋的值maxn,那我们就可以返回这个点的时间了。如果没返回,就继续上下左右遍历,更改点的坐标以及时间,如果这个点没出现过,而且他在第一象限,而且此时此刻的时间小于map里开始爆的时间,那就说明可以走这个点,就把这个点push到队列里,并做上标记

这个代码稍微改一点就wa,一次时main里那个t,不能写成map[i][j],还有一个是bfs里面参数的位置,稍微一改就错,具体错到哪我调试了两小时没调出来md以后干脆先建结点再判断吧,参数再for里for外if里if外这东西我头疼
代码参考:
https://blog.csdn.net/coraline_m/article/details/18035393

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int maxn=10000;
int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
int mp[305][305];
int visi[305][305];
struct node
{
    int x,y,t;//坐标和时间 
};

int bfs(int x,int y)//从00点开始 
{
    queue<node> mq;
    node nod; 
    nod.x=x,nod.y=y,nod.t=0;
    mq.push(nod);

    while(!mq.empty())
    {
        int cx,cy,px,py,time;
        nod=mq.front();
        mq.pop();
        cx=nod.x,cy=nod.y,time=nod.t;

        if(mp[cx][cy]==maxn)//没有被炸掉 
        {
            //cout<<time<<endl;
            return time;
        }
        for(int i=0;i<4;i++)//(0,0)上下左右跑 
        {
            px=cx+dir[i][0],py=cy+dir[i][1];
            nod.x=px,nod.y=py,nod.t=time+1;
            if(px>=0&&py>=0&&!visi[px][py]&&nod.t<mp[px][py])//nod。t小于他说明可以走这个点 
            {
                visi[px][py]=1;
                mq.push(nod);
            }
        }
    }

    return -1;
}

int main()
{
    int n,i,j;
    int x,y,tim,cx,cy;
    while(cin>>n)
    {
        for(i=0;i<304;i++)
            for(j=0;j<304;j++)
                mp[i][j]=maxn;
        while(n--)
        {
            scanf("%d%d%d",&x,&y,&tim);
            mp[x][y]=min(mp[x][y],tim);//mp存的是最早爆的时间 
            for(i=0;i<4;i++)// 他上下左右四个点位全爆掉 
            {
                cx=x+dir[i][0],cy=y+dir[i][1];
                if(cx>=0&&cy>=0)    mp[cx][cy]=min(mp[cx][cy],tim);//点在第一象限内 
            }
        }

        memset(visi,0,sizeof(visi));//初始化标志数组 
        visi[0][0]=1;
        int res=bfs(0,0);
        cout<<res<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40828914/article/details/81487347
今日推荐