poj3669 Meteor Shower

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

在一个矩形区域,区域大小为0<=X<=300, 0<=Y<=300,有所谓流星坠落,给出M个流星坠落的时间和地点,问最少需要多少时间步能走到一个安全的格子上,从而不会遭受流星的撞击。每个流星坠落在某一格点后,其相邻四个格点会遭到破坏。

样例输入

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

样例输出

5

思路

  • 假如起点(0,0)不会遭受到流星的攻击(也不会因为周围格子被攻击而延伸至它),那么也就不用移动就能保证安全。如果起点会受到攻击,不论是何时,我们都需要离开起点,那么哪里才是安全的终点呢?只要这个点上不会在有流星的攻击,这个点就是安全的终点,我们bfs出第一个安全的终点就是最少的时间步。
  • 根据输入我们可以标记每个受流星攻击的网格的时间,注意如果一个网格有多次被流星摧毁的时间,那么取最小的作为这个网格的摧毁时间,同时需要将这个网格上下左右四个网格也“以最近摧毁”原则更新被摧毁的时间。

代码

#include <iostream>
#include <memory.h>
#include <queue>
#include <utility>
using namespace std;
typedef pair<int, int> PII;

const int N = 302;
int dx[] = {0, 1, 0, -1};
int dy[] = {-1, 0, 1, 0};
int time[N][N];
int g[N][N];
int bfs(){
    time[0][0] = 0;
    if(time[0][0] >=  g[0][0]) return -1;   //如果起点在时间0就被炸了, 那么直接失败...
    if(g[0][0] == 0x3f3f3f3f) return 0;     //如果起点不会被炸, 那么就不用走了...
    queue<PII> q;                           
    q.push(make_pair(0, 0));
    int time_step = 0;
    while(!q.empty()){
        PII p = q.front(); q.pop();
        for(int i = 0; i < 4; ++i){
            int x = p.first + dx[i], y = p.second + dy[i];
            if(x >= 0 && x <= N && y >= 0 && y <= N){
                if(time[x][y] == -1){    //这个网格没有被访问过(不能走回头路)
                    time[x][y] = time[p.first][p.second] + 1;
                    if(g[x][y] == 0x3f3f3f3f){    //到达"终点"
                        return time[x][y];
                    }
                    if(time[x][y] < g[x][y] && g[x][y] != 0x3f3f3f3f) q.push(make_pair(x, y)); //如果这个网格要被炸但目前是安全的, 那么放入队列中
                }
            }
        }
    }
    return -1;
}

int main(){
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    int M; scanf("%d", &M);
    memset(g, 0x3f, sizeof(g));      //g记录网格被摧毁的时间T, 初始为正无穷(0x3f3f3f3f), 表示不会被摧毁
    memset(time, -1, sizeof(time));  //time记录到某一网格的时间步数,-1表示未访问
    while(M--){
        int x, y, t;
        scanf("%d%d%d", &x, &y, &t);
        if(g[x][y] > t) g[x][y] = t;
        for(int i = 0; i < 4; ++i){     //按"最近时间摧毁"原则记录每个网格被摧毁的时间
            int nx = x + dx[i], ny = y + dy[i];
            if(nx >= 0 && nx <= N && ny >= 0 && ny <= N){
                if(g[nx][ny] > t)
                    g[nx][ny] = t;
            }
        }
    }
    printf("%d", bfs());
}
posted @ 2020-01-14 22:26  patrolli  阅读(108)  评论(0编辑  收藏  举报