当前位置: 首页 > news >正文

【优选算法】多源BFS

在这里插入图片描述

  • 多源BFS简介
  • 一、[01 矩阵](https://leetcode.cn/problems/01-matrix/description/)
  • 二、[飞地的数量](https://leetcode.cn/problems/number-of-enclaves/description/)
  • 三、[地图中的最高点](https://leetcode.cn/problems/map-of-highest-peak/description/)
  • 四、[地图分析](https://leetcode.cn/problems/as-far-from-land-as-possible/description/)
  • 结尾

多源BFS简介

多源 BFS 是广度优先搜索(BFS)的一种扩展形式,核心思想是从多个初始节点同时出发,按照层次逐层向外扩展,适用于需要计算 “多个源点到其他节点的最短距离” 或 “全局最优解” 的场景。

单权(即所有边的权重相同,通常为 1)的情况下,多源 BFS 的优势尤为明显,因为 BFS 的 “逐层扩展” 特性天然保证了首次到达某节点时的距离就是最短距离。


一、01 矩阵

题目描述
在这里插入图片描述

思路讲解
本道题需要我们计算矩阵中每个 非0 到最近的 0 的距离,若正向搜索从 非0 到 0 的最近距离,需要我们找到最近 0 ,然后倒回去修改 非0 上的距离,这样会显得很麻烦,所以我们可以换一种思路,找到所有的 0 ,然后同时向外逐层扩展搜索,找到最近的 非0,并修改它的距离。以下是具体思路:

  1. 所有值为 0 的位置作为 BFS 的起点(初始队列),因为它们到自身的距离为 0。创建与原矩阵同等规模的矩阵 ans,初始化距离矩阵 ans,其中值为 0 的位置距离为 0,其余位置初始化为-1(表示尚未访问)

  2. 定义一个变量记录当前距离

  3. BFS逐层扩展搜索:

    • 记录当前队列中元素的个数为 cnt,并将距离 +1
    • 将以下步骤循环执行 cnt 次
      • 从队列中取出当前位置,遍历其上下左右四个相邻位置
      • 若相邻位置未被访问过,则更新其距离为当前距离 + 1,并将其加入队列
  4. 队列为空时,所有位置的最短距离均已计算完毕

编写代码

class Solution {int dx[4] = {0,0,-1,1};int dy[4] = {1,-1,0,0};
public:vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {int rows = mat.size() , cols = mat[0].size();vector<vector<int>> ans(rows,vector<int>(cols,-1));queue<pair<int,int>> qu;for(int i = 0 ; i < rows ; i++){for(int j = 0 ; j < cols ; j++){if(mat[i][j] == 0){qu.push({i,j});ans[i][j] = 0;}}}while(!qu.empty()){int qu_x = qu.front().first , qu_y = qu.front().second;qu.pop();for(int i = 0 ; i < 4 ; i++){int x = qu_x + dx[i] , y = qu_y + dy[i];if(x >= 0 && x < rows && y >= 0 && y < cols && mat[x][y] != 0 && ans[x][y] == -1){qu.push({x,y});ans[x][y] = ans[qu_x][qu_y] + 1;}}}return ans;}
};

二、飞地的数量

题目描述
在这里插入图片描述

思路讲解
本道题需要我们找到所有无法通过移动到达网格边界的陆地单元格(即被海洋完全包围的陆地)。但是想要正向判断是否无法通过移动到达网格边界的陆地单元格,需要先找到一个未被访问的陆地单元格,再通过一次BFS判断该区域是否被海洋包围,如果被海洋包围,则增加陆地单元格的数量。

这里还有一种方式我认为比上面一个方法更加简单。先找出所有不被围绕的陆地,并将这些陆地标记为已访问,剩下的陆地都是不被包围的,再遍历整个二维数组,记录剩下陆地的数量。

  1. 遍历二维数组中边缘四条边中的每个位置 [i, j] ,将所有陆地单元格的位置作为 BFS 的起点
  2. 创建与原矩阵同等规模的矩阵 vis,初始化距离矩阵 vis 为 false,表示尚未访问
  3. BFS 处理连通区域:
    • 记录当前队列中元素的个数为 cnt
    • 将以下步骤循环执行 cnt 次
      • 从队列中取出位置,遍历其上下左右四个方向的相邻位置
      • 对每个相邻位置,若在二维数组范围内且为陆地,将该位置标记为false,表示已访问,继续扩展处理
  4. 遍历二维数组,统计未被访问并且为陆地的数量
  5. 处理完毕后,返回陆地数量

编写代码

class Solution {int dx[4] = {0, 0, -1, 1};int dy[4] = {1, -1, 0, 0};public:int numEnclaves(vector<vector<int>>& grid) {int rows = grid.size(), cols = grid[0].size();vector<vector<bool>> vis(rows, vector<bool>(cols, false));queue<pair<int, int>> qu;for (int i = 0; i < rows; i++) {if (grid[i][0] == 1) {qu.push({i, 0});vis[i][0] = true;}if (grid[i][cols - 1] == 1) {qu.push({i, cols - 1});vis[i][cols - 1] = true;}}for (int i = 0; i < cols; i++) {if (grid[0][i] == 1) {qu.push({0, i});vis[0][i] = true;}if (grid[rows - 1][i] == 1) {qu.push({rows - 1, i});vis[rows - 1][i] = true;}}while (!qu.empty()) {int qu_x = qu.front().first, qu_y = qu.front().second;qu.pop();for (int i = 0; i < 4; i++) {int x = qu_x + dx[i], y = qu_y + dy[i];if (x >= 0 && x < rows && y >= 0 && y < cols &&grid[x][y] == 1 && vis[x][y] == false) {qu.push({x, y});vis[x][y] = true;}}}int ans = 0;for (int i = 1; i < rows - 1; i++) {for (int j = 1; j < cols - 1; j++) {if (grid[i][j] == 1 && vis[i][j] == false)ans++;}}return ans;}
};

三、地图中的最高点

题目描述
在这里插入图片描述

思路讲解
本道题需要我们为每个单元格分配高度,使得水域单元格高度为 0,相邻单元格高度差不超过 1,并且最高高度尽可能大。通过使用BFS从所有水域单元格同步向外扩展,可以确保每个陆地单元格的高度是到最近水域的最短距离。以下是具体思路:

  1. 将所有水域单元格(值为 1 的位置)加入 BFS 队列。创建与原二维数组同等规模的二维数组 ans,初始化二维数组 ans 高度,其中水域位置高度为 0,陆地位置初始为 - 1(表示未访问)
  2. 定义一个变量记录当前高度
  3. BFS逐层扩展搜索:
    • 记录当前队列中元素的个数为 cnt,并将高度 +1
    • 将以下步骤循环执行 cnt 次
      • 从队列中取出当前位置,遍历其上下左右四个相邻位置
      • 若相邻位置为未访问的陆地,则将其高度设为当前高度,并加入队列继续扩展
  4. 所有单元格的高度均已计算完毕,返回二维数组ans

编写代码

class Solution {int dx[4] = {0, 0, -1, 1};int dy[4] = {1, -1, 0, 0};public:vector<vector<int>> highestPeak(vector<vector<int>>& isWater) {int rows = isWater.size() , cols = isWater[0].size();vector<vector<int>> ans(rows,vector<int>(cols,-1));queue<pair<int,int>> qu;for(int i = 0 ; i < rows ; i++){for(int j = 0 ; j < cols ; j++){if(isWater[i][j] == 1){ans[i][j] = 0;qu.push({i,j});}}}while(!qu.empty()){int qu_x = qu.front().first , qu_y = qu.front().second;qu.pop();for(int i = 0 ; i < 4 ; i++){int x = qu_x + dx[i] , y = qu_y + dy[i];if(x >= 0 && x < rows && y >= 0 && y < cols && isWater[x][y] == 0 && ans[x][y] == -1){qu.push({x,y});ans[x][y] = ans[qu_x][qu_y] + 1;}}}return ans;}
};

四、地图分析

题目描述
在这里插入图片描述

思路讲解
本道题需要我们找到距离最近陆地最远的海洋单元格,并返回其曼哈顿距离。假设“从海洋找陆地”,两个相邻的海洋单元格可能会重复搜索同一区域的陆地,会导致重复计算和高时间复杂度。

这里我们换一种思路“从陆地找海洋”,通过从所有陆地单元格同步向外扩展,可以逐层计算每个海洋单元格到最近陆地的距离,最后取最大值即可。

  1. 将所有陆地单元格(值为 1 的位置)加入 BFS 队列,初始距离为 0。初始化距离矩阵ans,陆地位置距离为 0,海洋位置初始为 - 1(表示未访问)。
  2. 定一个变量记录最大距离,再定义一个变量记录当前距离
  3. BFS逐层扩展搜索:
    • 记录当前队列中元素的个数为 cnt,并将当前距离 +1
    • 将以下步骤循环执行 cnt 次
      • 从队列中取出当前位置,遍历其上下左右四个相邻位置
      • 若相邻位置为未访问的海洋,则将其距离设为当前距离,通过与最大距离对比,得到新的最大距离
      • 若相邻位置为未访问的海洋,将该位置设置为false,表示已访问,并将该位置加入队列继续扩展
  • 若所有单元格都是陆地或海洋,返回 - 1,反正则返回最大距离

编写代码

class Solution {int dx[4] = {0, 0, -1, 1};int dy[4] = {1, -1, 0, 0};
public:int maxDistance(vector<vector<int>>& grid) {int rows = grid.size() , cols = grid[0].size();vector<vector<bool>> vis(rows,vector<bool>(cols,false));queue<pair<int,int>> qu;for(int i = 0 ; i < rows ; i++){for(int j = 0 ; j < cols ; j++){if(grid[i][j] == 1){qu.push({i,j});vis[i][j] = true;}}}int ans = -1;while(!qu.empty()){ans++;int cnt = qu.size();while(cnt--){int qu_x = qu.front().first , qu_y = qu.front().second;qu.pop();for(int i = 0 ; i < 4 ; i++){int x = qu_x + dx[i] , y = qu_y + dy[i];if(x >= 0&& x < rows && y >= 0 && y < cols && grid[x][y] == 0 && vis[x][y] == false){qu.push({x,y});vis[x][y] = true;}}}}if(ans == 0) return -1;else return ans;}
};

结尾

如果有什么建议和疑问,或是有什么错误,大家可以在评论区中提出。
希望大家以后也能和我一起进步!!🌹🌹
如果这篇文章对你有用的话,希望大家给一个三连支持一下!!🌹🌹
在这里插入图片描述

http://www.dtcms.com/a/320642.html

相关文章:

  • C#调用Unity实现设备仿真开发
  • Java+uniapp+websocket实现实时聊天,并保存聊天记录
  • (nice!!!)(LeetCode 每日一题) 808. 分汤 (深度优先搜索dfs)
  • Latex中公式部分输入正体的字母\mathrm{c}
  • [激光原理与应用-183]:测量仪器 - 光束型 - 光束参数乘积(BPP)的本质与含义,聚焦能力与传输稳定性的物理矛盾。
  • 汽车零部件深孔加工质控升级:新启航激光频率梳 3D 测量解决传统光学扫描遮挡
  • Linux网络--2、Socket编程
  • 力扣-238.除自身以外数组的乘积
  • 《Leetcode》-面试题-hot100-链表
  • 力扣热题100------287.寻找重复数
  • 大语言模型提示工程与应用:提示词基础使用方式
  • 9.2 通过DuEDrawingControl把eDrawing嵌入到C#中显示
  • windows线程基础
  • leetcode热题——有效的括号
  • FPS游戏准心跳动效果实现指南
  • 为什么通过CreateThread创建的线程调用C/C++运行库函数不稳定
  • Sum of Four Values(sorting and searching)
  • 力扣-438.找到字符串中所有字母异位词
  • I/O原理与服务。
  • KTH7111-离轴专用芯片,支持自校准,可替MA600和TLE5012,离轴精度可达±0.2
  • Agent配置最佳实践:Prompt工程与参数调优
  • RAG初步实战:从 PDF 到问答:我的第一个轻量级 RAG 系统(附详细项目代码内容与说明)
  • WWDC 25 玻璃态星际联盟:SwiftUI 视图协同“防御协议”
  • 生产管理ERP系统|物联及生产管理ERP系统|基于SprinBoot+vue的制造装备物联及生产管理ERP系统设计与实现(源码+数据库+文档)
  • 2025华数杯数学建模A题【 多孔膜光反射性能的优化与控制】原创论文分享
  • 暴力解决MySQL连接失败
  • 应用层自定义协议
  • Spring系列之Spring AI入门
  • 关于“致命错误:‘https://github.com/....git/‘ 鉴权失败”
  • 基于Vue.js和Golang构建高效在线客服系统:前端实现与后端交互详解