poj 3669 (BFS)

 题目链接http://poj.org/problem?id=3669

这道题跟我其实有很深的渊源呀,第一次做的时候用的是模拟法,就是对流星下落的时间进行排序,然后模拟每个流星下落的过程,以及人的运动,十分繁琐,经过了WA,RE,最后一直TLE过不了...... 之后放了有一个月,这几天又拿出来,想了一个更简洁的方法,最后AC掉。

思路先将Map初始化为INF,然后将每颗流星下落的时间标记在Map上,对于同一位置多颗流星撞击,取其中的最小值,然后从起始位置进行宽度优先搜索,直到找到位置上为INF位置。

这道题同时也体现出细节的力量,BFS中有一个细节,就是判断当前状态是否是INF状态,

一种是在从队列中取出状态的时候,

    while(que.size()){
       Bes=que.front();
       que.pop();
       if(Map[Bes.x][Bes.y]==INF) return Bes.t;
       Map[Bes.x][Bes.y]=0;
       for(int i=0;i<4;i++){
            iii mid;
            mid.x=Bes.x+dir[i][0];
            mid.y=Bes.y+dir[i][1];
            mid.t=Bes.t+1;
            if(mid.t<Map[mid.x][mid.y]) que.push(mid);
       }
    }

 

一种是在加入队列之前,

 

    while(que.size()){
       Bes=que.front();
       que.pop();
       for(int i=0;i<4;i++){
            iii mid;
            mid.x=Bes.x+dir[i][0];
            mid.y=Bes.y+dir[i][1];
            mid.t=Bes.t+1;
            if(Map[mid.x][mid.y]==INF) return mid.t;
            if(Map[mid.x][mid.y]<=mid.t) continue;
            Map[mid.x][mid.y]=0;
            que.push(mid);
       }
    }

 


这两种不同的方法在运行时间上相差很大,不知道是题的原因还是本身就存在差异,我先是用的第一种方法,结果一直是TLE,感觉实在无解,去搜了题解直到了第二种方法,结果94ms就过了~~~~

还有一些细节见code了

code:

//poj 3669
//广度优先搜索
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <queue>

using namespace std;
#define SIZE 405//注意范围,题目给的范围是流星的范围并不是活动的范围,所以数组应该开得更大一些
#define INF 10000000

struct NODE
{
    int x,y,t;
};
typedef struct NODE iii;
int Map[SIZE][SIZE];
int dir[5][2]={{0,1},{0,-1},{-1,0},{1,0},{0,0}}; //表示上 下 左 右 中五个方向
queue<iii> que;// 在此申请了一个iii类型的队列
iii Bes;
void initial()
{
    for(int i=0;i<SIZE;i++){
        for(int j=0;j<SIZE;j++){
            //为了防止出界 将活动区域之外 又围了一圈
            if(!i||!j||(i==SIZE-1)||(j==SIZE-1)) Map[i][j]=0;
            else Map[i][j]=INF;
        }
    }
    Bes.x=1;//因为活动区域的变化 所以其实位置也得变化
    Bes.y=1;
    Bes.t=0;
    que.push(Bes);
    int midx,midy,midt,N; //用于输入时对地图的处理
    scanf("%d",&N);
    while(N--){
        scanf("%d%d%d",&midx,&midy,&midt);
        midx++;//为了防止越界 全部都是x,y都是从1开始的
        midy++;
        for(int i=0;i<5;i++){
            if(Map[midx+dir[i][0]][midy+dir[i][1]]>midt){
                Map[midx+dir[i][0]][midy+dir[i][1]]=midt;
            }
        }
    }
    return ;
}
int BFS()
{
    if(Map[1][1]==0) return -1;
    if(Map[1][1]==INF) return 0;
    while(que.size()){
       Bes=que.front();
       que.pop();
       for(int i=0;i<4;i++){
            iii mid;
            mid.x=Bes.x+dir[i][0];
            mid.y=Bes.y+dir[i][1];
            mid.t=Bes.t+1;
            if(Map[mid.x][mid.y]==INF) return mid.t;
            if(Map[mid.x][mid.y]<=mid.t) continue;
            Map[mid.x][mid.y]=0;
            que.push(mid);
       }
    }
    return -1;
}
int main()
{
    initial();
    printf("%d\n",BFS());
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值