多源BFS
多源BFS
对于一般的BFS,其只有单源的入口节点,然后按照BFS套路,从而求出最短路之类的问题。
下面介绍的是对于含有多个入口节点,且需要求最短路径之类的问题。
样题模型
[ACWing 173]
给定一个 N 行 M 列的 01 矩阵 A,A[i][j] 与 A[k][l] 之间的曼哈顿距离定义为:
dist(A[i][j],A[k][l])=|i−k|+|j−l|
输出一个 N 行 M 列的整数矩阵 B,其中:
输入格式
第一行两个整数 N,M。
接下来一个 N 行 M 列的 01 矩阵,数字之间没有空格。
输出格式
一个 N 行 M 列的矩阵 B,相邻两个整数之间用一个空格隔开。
数据范围
1≤N,M≤1000
输入样例:
3 4
0001
0011
0110
输出样例:
3 2 1 0
2 1 0 0
1 0 0 1
[分析]:常规思路,是对每个A[i][j] == 1的点,进行一次BFS,每次更新的点保留最小值,这样经过多次BFS之后,就可以得到答案。
因为数据规模是1000X1000,所以基本上可通过的算法时间复杂度为O(n), 而采用上述常规思路,可达O(n^2),这是不可取的。
一种更加优化的方式是: 假象存在一个虚拟起始点,其到每个A[i][j] =1的位置都存在一条边,这样的边权都为0,那么就是可将多源的BFS问题转换为单源BFS问题。
还有一种理解方式是参考Dijkstra算法,只不过因为我们入队时就已经保证了队头元素最小,不需要用堆来保存数据,这样就退化成用队的Dijkstra算法,然后求最短路。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int N = 1000 + 10;
int A[N][N];
int n, m;
typedef pair<int, int> PII;
queue<PII> qu;
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
void BFS()
{
while (!qu.empty()) {
auto head = qu.front();
qu.pop();
int x = head.first, y = head.second;
for (int i = 0; i < 4; i++) {
int a = x + dx[i], b= y + dy[i];
if (a >= 0 && a < m && b >= 0 && b < n && A[a][b] == -1) {
qu.push({a, b});
A[a][b] = A[x][y] + 1;
}
}
}
}
int main()
{
cin >> m >> n;
string s;
for (int i = 0; i < m ; i++) {
cin >> s;
for (int j = 0; j < s.size(); j++) {
A[i][j] = s[j] - '0';
}
}
for (int i = 0; i < m ; i++) {
for (int j = 0; j < n; j++) {
if (A[i][j] == 1) {
qu.push({i, j});
A[i][j] = 0;
} else {
A[i][j] = -1;
}
}
}
BFS();
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (j != n)
cout << A[i][j] << " " ;
else
cout << A[i][j];
}
cout << endl;
}
return 0;
}
样题2【leetcode1765】
本质上换汤不换药,直接套一下完事;
class Solution {
public:
typedef pair<int, int> PII;
int m, n;
vector<vector<int>> highestPeak(vector<vector<int>>& isWater) {
m = isWater.size(), n = isWater[0].size();
queue<PII> qu;
for (int i = 0; i < isWater.size(); i++) {
for (int j = 0; j < isWater[i].size(); j++) {
if (isWater[i][j] == 1) {
qu.push(make_pair(i, j));
isWater[i][j] = 0;
} else {
isWater[i][j] = -1;
}
}
}
BFS(qu, isWater);
return isWater;
}
int dx[4] = {1, 0, 0, -1};
int dy[4] = {0, 1, -1, 0};
void BFS(queue<PII>& qu, vector<vector<int>>& isWater)
{
while (qu.size()) {
auto head = qu.front();
qu.pop();
int x = head.first, y = head.second;
for (int i = 0; i < 4; i++) {
int a = x + dx[i], b = y + dy[i];
if (a >= 0 && a < m && b >= 0 && b < n && isWater[a][b] == -1) {
qu.push({a, b});
isWater[a][b] = isWater[x][y] + 1;
}
}
}
}
};
样题3 【leetcode 1162】
只需要将 0-1对调一下,套用1765的代码即可;
class Solution {
public:
typedef pair<int, int> PII;
int m, n;
int maxDistance(vector<vector<int>>& grid) {
int ans = -1;
m = grid.size(), n = grid[0].size();
queue<PII> qu;
for (int i = 0; i < grid.size(); i++) {
for (int j = 0; j < grid[0].size(); j++) {
if (grid[i][j] == 0) {
grid[i][j] = -1;
} else {
grid[i][j] = 0;
qu.push({i, j});
}
}
}
BFS(qu, grid, ans);
return ans;
}
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
void BFS(queue<PII> & qu, vector<vector<int>>& grid, int& ans)
{
while (!qu.empty()) {
auto head = qu.front();
qu.pop();
int x = head.first, y = head.second;
for (int i = 0; i < 4; i++) {
int a = x + dx[i], b = y + dy[i];
if (a >= 0 && a < m && b >= 0 && b < n && grid[a][b] == -1) {
qu.push({a, b});
grid[a][b] = grid[x][y] + 1;
ans = max(grid[a][b], ans);
}
}
}
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效