P2895 [USACO08FEB] Meteor Shower S
题目理解
这道题目描述了一个牧场上的流星雨场景,贝茜需要从原点(0,0)出发,寻找一个永远不会被流星击中的安全位置。每个流星会在特定时间击中某个坐标,并摧毁该位置及其上下左右相邻的四个格子。贝茜每单位时间可以移动一格,但不能进入已被摧毁或即将被摧毁的格子。
解题思路
- 
预处理流星影响:首先记录每个格子最早被流星摧毁的时间。如果一个格子不会被任何流星摧毁,则标记为-1。 
- 
广度优先搜索(BFS):从起点(0,0)开始进行BFS,记录到达每个格子的时间。在移动时,必须确保到达该格子的时间早于该格子被摧毁的时间。 
- 
安全位置判断:在BFS过程中,如果遇到一个永远不会被摧毁的格子(G[xx][yy] == -1),则立即返回当前时间作为答案。如果队列为空仍未找到安全位置,则返回-1。 
参考代码
#include<bits/stdc++.h>
#define N 305  // 定义坐标的最大范围
#define endl "\n"
using namespace std;
// 定义坐标和时间结构体
struct node {
    int x, y, t;
};
queue<node> q;      // BFS使用的队列
int G[N][N];        // 记录每个格子被摧毁的最早时间,-1表示安全
int vis[N][N];      // 标记数组,记录是否访问过
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}; // 四个方向的移动增量
int n, m;           // n未使用,m是流星数量
bool f;             // 标记是否找到安全位置
// 广度优先搜索函数,从(sx,sy)出发寻找安全位置
void bfs(int sx, int sy) {
    node s = {sx, sy, 0};  // 起点,时间为0
    vis[s.x][s.y] = 1;     // 标记为已访问
    q.push(s);             // 入队
    
    while (!q.empty()) {
        s = q.front();
        // 检查四个方向
        for (int i = 0; i < 4; i++) {
            int xx = s.x + dx[i], yy = s.y + dy[i], tt = s.t + 1;
            // 如果找到安全位置
            if (G[xx][yy] == -1 && xx >= 0 && yy >= 0) {
                cout << tt << endl; // 输出到达时间
                f = 1;             // 标记已找到
                return;
            }
            // 如果新位置在有效范围内、未被访问过,且到达时间早于被摧毁时间
            if (xx >= 0 && yy >= 0 && vis[xx][yy] == 0 && tt < G[xx][yy]) {
                vis[xx][yy] = 1;   // 标记为已访问
                q.push({xx, yy, tt}); // 入队继续搜索
            }
        }
        q.pop();
    }
}
int main() {
    cin >> m; // 输入流星数量
    memset(G, -1, sizeof(G)); // 初始化所有格子为安全状态
    // 处理每个流星的影响
    while (m--) {
        int x, y, t;
        cin >> x >> y >> t;
        // 更新流星撞击点的时间(取最早时间)
        if (x >= 0 && y >= 0 && (t < G[x][y] || G[x][y] == -1)) {
            G[x][y] = t;
        }
        // 更新四个相邻格子的时间
        for (int i = 0; i < 4; i++) {
            int xx = x + dx[i], yy = y + dy[i];
            if (xx >= 0 && yy >= 0 && (t < G[xx][yy] || G[xx][yy] == -1)) {
                G[xx][yy] = t;
            }
        }
    }
    // 检查起点状态
    if (G[0][0] == 0) { // 起点一开始就被摧毁
        cout << -1;
        return 0;
    }
    if (G[0][0] == -1) { // 起点本身就是安全位置
        cout << 0;
        return 0;
    }
    bfs(0, 0); // 从起点开始BFS
    if (!f) cout << -1; // 未找到安全位置
    return 0;
}总结
这道题的关键在于:
- 
预处理每个格子的最早被摧毁时间 
- 
使用BFS进行最短路径搜索时,需要考虑时间限制条件 
- 
及时终止条件(找到第一个安全位置) 
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号