P2895 [USACO08FEB] Meteor Shower S 时限BFS
解题思路
这道题是一个典型的带时间限制的BFS问题,需要考虑流星坠落时间对路径选择的影响。关键点在于:
-
地图预处理:首先计算每个格子最早被流星摧毁的时间
-
安全区域判断:安全区域是指永远不会被流星摧毁的格子(即g[x][y] = ∞)
-
BFS扩展条件:贝茜只能在到达某格子的时间早于该格子被摧毁的时间才能移动
-
边界处理:注意坐标不能为负值
代码注释
#include<bits/stdc++.h> using namespace std; const int N = 3e2 + 10; // 定义地图最大尺寸 const int inf = 0x3f3f3f3f; // 定义无穷大值 // 定义节点结构体,存储坐标和步数 struct node { int x, y, step; // x,y是坐标,step是到达该点的步数 }; int g[N][N]; // 存储每个格子最早被摧毁的时间 int vis[N][N]; // 访问标记数组 int nex[4][2] = {{0,1}, {1,0}, {0,-1}, {-1,0}}; // 四个移动方向:右、下、左、上 int m; // 流星数量 // BFS函数,从起点(sx,sy)开始搜索 void bfs(int sx, int sy) { queue<node> q; // 创建队列用于BFS vis[sx][sy] = 1; // 标记起点已访问 q.push({sx, sy, 0}); // 起点入队,初始步数为0 while(q.size()) { // 当队列不为空时循环 node h = q.front(); q.pop(); // 取出队首元素 // 尝试四个方向移动 for(int i = 0; i < 4; i++) { int tx = h.x + nex[i][0]; // 计算新坐标x int ty = h.y + nex[i][1]; // 计算新坐标y // 边界检查:坐标不能为负 if(tx < 0 || ty < 0) continue; // 检查移动时间是否早于被摧毁时间且未访问过 if(h.step + 1 >= g[tx][ty] || vis[tx][ty]) continue; vis[tx][ty] = 1; // 标记为已访问 q.push({tx, ty, h.step + 1}); // 新位置入队,步数+1 // 如果到达安全区域(永远不会被摧毁的格子) if(g[tx][ty] == inf) { cout << h.step + 1; // 输出当前步数 return; // 直接返回 } } } // 如果队列为空仍未找到安全区域,输出-1 cout << "-1"; } int main() { // 初始化所有格子为无穷大(表示初始都是安全的) memset(g, 0x3f3f3f3f, sizeof(g)); // 读取流星数量 cin >> m; // 处理每个流星 for(int i = 1; i <= m; i++) { int x, y, z; cin >> x >> y >> z; // 读取流星坐标和坠落时间 // 更新流星撞击点最早被摧毁时间 g[x][y] = min(g[x][y], z); // 更新流星影响的周围4个格子 for(int k = 0; k < 4; k++) { int tx = x + nex[k][0], ty = y + nex[k][1]; if(tx < 0 || ty < 0) continue; // 边界检查 g[tx][ty] = min(g[tx][ty], z); // 更新最早被摧毁时间 } } // 执行BFS搜索,从原点(0,0)开始 bfs(0, 0); return 0; }

浙公网安备 33010602011771号