我爱学算法之—— 多源BFS

前言

所谓多源BFS,简单来说就从多个起点开始遍历。

一、01 矩阵

题目解析

给定一个由01组成的矩阵,要输出一个大小相同的矩阵,结果矩阵中每一个格子都是mat中对应位置到最近的0的距离。

算法思路

这道题如果从1位置开始遍历,那就只能一个一个进行BFS 求到最近的0的距离,那未免也太复杂的。

但如果从0位置开始遍历,我们就可以在一开始将所有的0位置放入到队列中,同时进行BFS,并且择优选择(统计每个位置是否遍历过,去重);

这样进行多源BFS后,1位置对应结果矩阵中的值就是该位置到最近0的距离。

代码实现

cpp 复制代码
class Solution {
public:
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    typedef pair<int, int> PII;
    vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
        int n = mat.size();
        int m = mat[0].size();
        queue<PII> q;
        vector<vector<int>> ret(n, vector<int>(m, -1));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (mat[i][j] == 0) {
                    q.push({i, j});
                    ret[i][j] = 0;
                }
            }
        }
        while(q.size() > 0)
        {
            int sz = q.size();
            while(sz--)
            {
                auto [a,b] = q.front();
                q.pop();
                for(int i = 0;i<4;i++)
                {
                    int x = a + dx[i];
                    int y = b + dy[i];
                    if(x>=0 && x<n && y>= 0 && y<m && ret[x][y] == -1)
                    {
                        q.push({x,y});
                        ret[x][y] = ret[a][b] + 1;
                    }
                }
            }
        }
        return ret;
    }
};

二、飞地的数量

题目解析

这道题和被围绕的区域非常类似,都是找围绕的区域;这里要求被围绕区域的陆地单元格个数。

算法思路

这道题思路也很明了了,先进行边缘处理,从边缘位置中的1开始进行BFS 遍历,进行标记,然后统计没有被标记的1的个数即可。

但这里边缘位置的1有很多,这里也不需要一个一个进行BFS 遍历,直接将所有边缘的1的下标放入队列中,进行多源BFS即可。

标记边界连通的陆地

  • 遍历矩阵的四条边界,将所有边界上的陆地(值为 1)加入队列,并标记为 0。
  • 通过 BFS 从这些边界陆地出发,向四周扩散,将所有能连通到边界的陆地标记为 0。

统计剩余陆地

  • 遍历整个矩阵,统计值仍为 1 的格子数量,即为飞地数量。

代码实现

cpp 复制代码
class Solution {
public:
    typedef pair<int, int> PII;
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    int numEnclaves(vector<vector<int>>& grid) {
        int n = grid.size();
        int m = grid[0].size();
        queue<PII> q;
        for (int i = 0; i < n; i++) {
            if (grid[i][0] == 1) {
                q.push({i, 0});
                grid[i][0] = 0;
            }

            if (grid[i][m - 1] == 1) {
                q.push({i, m - 1});
                grid[i][m - 1] = 0;
            }
        }
        for (int i = 0; i < m; i++) {
            if (grid[0][i] == 1) {
                q.push({0, i});
                grid[0][i] = 0;
            }
            if (grid[n - 1][i] == 1) {
                q.push({n - 1, i});
                grid[n - 1][i] = 0;
            }
        }
        while (q.size() > 0) {
            int sz = q.size();
            while (sz--) {
                auto [a, b] = q.front();
                q.pop();
                for (int i = 0; i < 4; i++) {
                    int x = a + dx[i];
                    int y = b + dy[i];
                    if (x >= 0 && x < n && y >= 0 && y < m && grid[x][y] == 1) {
                        q.push({x, y});
                        grid[x][y] = 0;
                    }
                }
            }
        }
        int ret = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == 1)
                    ret++;
            }
        }
        return ret;
    }
};

三、地图中的最高点

题目解析

这道题是要根据给定的m×n整数矩阵isWater(0 表示陆地、1 表示水域),给每个格子安排非负高度,满足:水域高度必须为 0;相邻格子(正东、南、西、北方向)高度差至多为 1。最终要找出使矩阵最高高度最大的高度安排方案,返回对应的高度矩阵height

算法思路

对于这道题,就不能像上面那样一次一次进行BFS遍历能解决了;

这里就只能同时从多个0位置开始遍历,让相邻格子的高度比当前位置高度大1

  • 水域是高度起点(0),陆地高度由「离最近水域的距离」决定(距离越远高度越高,且满足相邻差≤1)。
  • 多源 BFS:所有水域同时入队,按层级扩散(同一层级高度相同),确保每个格子首次被访问时的高度是最小可行高度,最终整体最高。

多源BFS

  • 初始化:高度矩阵 high 全设为 - 1(未赋值),遍历矩阵,将所有水域坐标设为 0 并加入队列。
  • BFS 遍历:出队当前格子,遍历 4 个相邻方向,若相邻格子是未赋值的陆地(high==-1),则其高度设为当前格子高度 + 1,入队继续扩散。
  • 返回高度矩阵 high。

代码实现

cpp 复制代码
class Solution {
public:
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    typedef pair<int, int> PII;
    vector<vector<int>> highestPeak(vector<vector<int>>& isWater) {
        int n = isWater.size();
        int m = isWater[0].size();
        queue<PII> q;
        vector<vector<int>> high(n, vector<int>(m, -1));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (isWater[i][j] == 1) {
                    high[i][j] = 0;
                    q.push({i, j});
                }
            }
        }
        while (q.size() > 0) {
            int sz = q.size();
            while (sz--) {
                auto [a, b] = q.front();
                q.pop();
                for (int i = 0; i < 4; i++) {
                    int x = a + dx[i];
                    int y = b + dy[i];
                    if (x >= 0 && x < n && y >= 0 && y < m &&
                        high[x][y] == -1) {
                        high[x][y] = high[a][b] + 1;
                        q.push({x, y});
                    }
                }
            }
        }
        return high;
    }
};

四、地图分析

题目解析

这道题是要在 n×n 的网格 grid 中(0 代表海洋,1 代表陆地),找出一个海洋单元格,使得它到离它最近的陆地单元格的曼哈顿距离最大,返回这个最大距离。如果网格只有陆地或只有海洋,返回 -1。

算法思路

对于这道题,就要从所有的1陆地,进行多源BFS遍历。

  • 所有陆地同时作为 BFS 起点(多源),按层级扩散(每一层对应距离 + 1),确保海洋首次被访问时的距离是 "最近陆地距离"。
  • 扩散过程中直接修改原网格(海洋置 1),避免额外访问标记数组。

多源BFS

  • 初始化:遍历网格,所有陆地(1)入队;若全是陆地 / 全是海洋,直接返回 - 1。
  • BFS 层级遍历:每轮扩散前距离 + 1(初始 - 1,首轮扩散后为 0,对应陆地相邻海洋的距离),遍历当前队列中所有陆地的 4 个相邻方向。
  • 若相邻是海洋(0),标记为 1(已访问)并入队,继续扩散。
  • 遍历结束后,返回最终累计的距离(即最大最近距离)。

代码实现

cpp 复制代码
class Solution {
public:
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    typedef pair<int, int> PII;
    int maxDistance(vector<vector<int>>& grid) {
        int n = grid.size();
        int m = grid[0].size();
        queue<PII> q;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == 1)
                    q.push({i, j});
            }
        }
        if(q.empty() || q.size() == n*m)
            return -1;
        int ret = -1;
        while (q.size() > 0) {
            ret++;
            int sz = q.size();
            while (sz--) {
                auto [a, b] = q.front();
                q.pop();
                for (int i = 0; i < 4; i++) {
                    int x = a + dx[i];
                    int y = b + dy[i];
                    if (x >= 0 && x < n && y >= 0 && y < m && grid[x][y] == 0) {
                        grid[x][y] = 1;
                        q.push({x, y});
                    }
                }
            }
        }
        return ret;
    }
};

本篇文章到这里就结束了,感谢支持

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2oul0hvapjsws

相关推荐
WWZZ20252 小时前
快速上手大模型:深度学习11(数据增强、微调、目标检测)
人工智能·深度学习·算法·目标检测·计算机视觉·大模型·具身智能
fashion 道格3 小时前
深入理解队列的艺术
数据结构·算法
大白IT3 小时前
第四部分:决策规划篇——汽车的“大脑”(第8章:行为决策——车辆的“驾驶策略师”)
人工智能·算法·机器学习
minji...3 小时前
C++ AVL树(二叉平衡搜索树)的概念讲解与模拟实现
数据结构·c++·b树·算法·avl
CNRio3 小时前
ZUC国密算法深度研究:原理、实现与应用(Python、Rust)
python·算法·rust
星期天23 小时前
【无标题】
数据结构·c++·算法
老李四3 小时前
Java 内存分配与回收策略
java·jvm·算法
做怪小疯子4 小时前
LeetCode 热题 100——普通数组——除自身以外数组的乘积
数据结构·算法·leetcode
稚辉君.MCA_P8_Java5 小时前
DeepSeek Java 插入排序实现
java·后端·算法·架构·排序算法