详细介绍:我爱学算法之—— 多源BFS

前言

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

一、01 矩阵

题目解析

在这里插入图片描述

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

算法思路

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

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

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

代码实现

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 的格子数量,即为飞地数量。

代码实现

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。

代码实现

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(已访问)并入队,继续扩散。
  • 遍历结束后,返回最终累计的距离(即最大最近距离)。

代码实现

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

posted @ 2025-12-19 17:09  gccbuaa  阅读(0)  评论(0)    收藏  举报