P1332 血色先锋队复盘

血色先锋军(多源 BFS)题解复盘

基本信息

项目内容
题目编号、来源血色先锋军
训练层级B BFS进阶
知识版块BFS、多源 BFS、网格搜索

解题前・关键信号识别

维度分析
目标、约束、底层结构目标:给定多个感染源,求每个领主被感染的最短时间;约束:n,m ≤ 500,a,b ≤ 1e5;底层结构:多个起点同时扩散,每个格子被第一次到达的时间即为感染时间。
数据规模n×m ≤ 250000,BFS 完全可行。
候选算法和依据多源 BFS;依据:多个感染源同时向四周扩散,每个格子被最早到达的时间就是感染时间。
复杂度预判时间复杂度 O(n×m),空间复杂度 O(n×m)。

解题后・外化复盘

维度内容
实现结构 / 核心思路第一步将所有感染源坐标存入队列,标记vis[x][y]=1,感染时间v[x][y]=0;第二步从队列中取出点,枚举 4 个方向;第三步若邻居未访问(vis[nx][ny]==0),则v[nx][ny]=v[x][y]+1,标记访问并入队;第四步最后按输入顺序输出每个领主的v[x][y]核心思想:多源 BFS 从所有起点同时出发,第一次到达即为最短时间,天然模拟“瘟疫扩散”过程。
错因回溯1. 用单源 BFS 对每个领主分别搜索,导致超时;2. 忘记标记vis导致重复入队;3. 坐标边界判断写错(nx<=0而非nx<0);4. 读取领主时没有单独存储,导致输出顺序错误。
边界和易错点1. 起点(感染源)的感染时间为 0;2. 入队时立即标记vis,防止重复入队;3. 输出顺序必须与输入顺序一致,所以需要先存储所有领主;4. 坐标从 1 开始,边界判断为nx<1 || nx>n || ny<1 || ny>m
下次看到什么信号,我应该想到这个方法看到「多个起点 + 同时扩散 + 求最短时间/距离」,用多源 BFS。

AC 完整代码

#include<iostream>#include<cstring>#include<queue>#include<algorithm>#include<set>#include<vector>usingnamespacestd;intv[505][505];intvis[505][505];set<pair<int,int>>s1;vector<pair<int,int>>s2;intdx[]={-1,0,1,0};intdy[]={0,1,0,-1};intn,m,a,b;voidbfs(){queue<pair<int,int>>q;for(auto&s:s1){intx=s.first;inty=s.second;q.push({x,y});vis[x][y]=1;}while(!q.empty()){auto[x,y]=q.front();q.pop();for(inti=0;i<4;i++){intnx=x+dx[i];intny=y+dy[i];if(nx<=0||nx>n||ny<=0||ny>m)continue;if(vis[nx][ny]==0){v[nx][ny]=v[x][y]+1;q.push({nx,ny});vis[nx][ny]=1;}}}}intmain(){cin>>n>>m>>a>>b;for(inti=0;i<a;i++){intx,y;cin>>x>>y;s1.insert({x,y});}for(inti=0;i<b;i++){intx,y;cin>>x>>y;s2.push_back({x,y});}bfs();for(auto&s:s2){intx=s.first;inty=s.second;cout<<v[x][y]<<endl;}return0;}