多源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,其中:

B[i][j]=min1xN,1yM,A[x][y]=1dist(A[i][j],A[x][y])
输入格式
第一行两个整数 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);
                }
            }
        }
    }
};

参考

  1. ACwing
  2. https://leetcode-cn.com/problems/as-far-from-land-as-possible/solution/gong-shui-san-xie-ru-he-shi-yong-duo-yua-vlea/
posted @   zhanghanLeo  阅读(628)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示