多源BFS

目录

算法原理

多源BFS步骤:

1、542. 01 矩阵

2、1020. 飞地的数量

3、1765. 地图中的最高点

4、1162. 地图分析


多源BFS(Breadth-First Search,广度优先搜索)是解决边权为1的多源最短路径问题的有效算法。在这种情况下,我们有多个起点,目标是找到从任何起点到图中任何其他点的最短路径。与传统的单源BFS相比,多源BFS同时从所有的起点开始搜索,这样可以一次性解决多个起点到所有其他点的最短路径问题。

算法原理

多源BFS的核心思想是同时从所有起点开始搜索,逐层向外扩展,直到遍历完所有可达的节点。算法的关键在于维护一个队列,队列中初始化时包含所有的起点。随后,算法按照广度优先的顺序访问节点,并逐步向外扩展。

假设我们有一个5x5的网格,网格中有几个起点(标记为S)和一个目标点(标记为T)。我们希望找到从任何一个起点到达目标点的最短路径。

+---+---+---+---+---+
| S |   |   |   |   |
+---+---+---+---+---+
|   | X | X | X |   |
+---+---+---+---+---+
|   | X | S | X |   |
+---+---+---+---+---+
|   |   |   | X |   |
+---+---+---+---+---+
|   |   | T |   |   |
+---+---+---+---+---+

在这个网格中,X表示障碍,不能通过。我们的目标是找到从任何一个S到T的最短路径。

多源BFS步骤:

  1. 初始化队列:将所有起点S的坐标放入队列中。
  2. 开始搜索:从队列中取出一个节点,探索它的上下左右四个方向的邻居节点。
  3. 扩展邻居节点:如果邻居节点是可达的(即不是X),并且未被访问过,则将它们加入队列,并标记为已访问。
  4. 重复步骤2和3:继续从队列中取出节点并探索,直到队列为空或找到目标点T

通过上面的步骤,我们可以同时从所有起点开始搜索,并在找到目标点时停止。这种方式保证了我们找到的路径是最短的,因为BFS是按层次扩展的,第一次到达目标点的路径一定是最短路径。

想象上面的网格,我们从所有的S开始,先将所有S加入队列。然后,我们一层层地向外扩展,直到找到目标点T。在扩展的过程中,我们绕过了障碍X,并找到了到达T的最短路径。

多源BFS的优势在于其简洁性和有效性,特别是当我们需要从多个起点到达目标点时,它能够提供一种直接且高效的解决方案。

1、542. 01 矩阵

思路:多源bfs 

在处理由0和1组成的矩阵并计算每个元素到最近的0的距离时,可以采用一种高效的方法:广度优先搜索(BFS)这个问题可以被视为一个多源最短路径问题,其中0的位置是源点

算法的核心思路是从所有的0开始进行层序遍历(广度优先搜索),而不是从1开始。这样做的好处是可以避免重复遍历同一个元素多次,从而提高效率。具体操作如下:

  1. 初始化一个与原矩阵同大小的矩阵dist,用于记录到最近0的距离。初始时,将所有元素设置为-1,表示尚未计算距离。对于矩阵中的0元素,其在dist中的对应位置被设置为0,表示自身到自身的距离为0。

  2. 将所有0元素的坐标同时加入到一个队列中,视它们为同一层的元素。这样,我们可以同时处理所有的0,以它们为起点向外扩散。

  3. 通过队列进行层序遍历。对于队列中的每个元素,检查其上下左右四个方向的邻居。如果某个邻居的距离还未被计算(即dist值为-1),则更新该邻居的距离为当前元素的距离加1,并将该邻居坐标加入队列中,以便进一步扩散。

  4. 继续这个过程,直到队列为空。此时,dist矩阵中的每个元素都存储了到最近的0的距离。

class Solution {
public:int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {int m = mat.size(), n = mat[0].size();// dist[i][j] == -1 表⽰:没有搜索过// dist[i][j] != -1 表⽰:最短距离vector<vector<int>> dist(m, vector<int>(n, -1));queue<pair<int, int>> q;for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (mat[i][j] == 0) {// 值为0的坐标一起入队,属于同一层同时处理(多源)q.push(make_pair(i, j));dist[i][j] = 0;}}}while (q.size()) {auto a = q.front();q.pop();for (int i = 0; i < 4; i++) {int x = dx[i] + a.first, y = dy[i] + a.second;if (x >= 0 && x < m && y >= 0 && y < n && dist[x][y] == -1) {dist[x][y] = dist[a.first][a.second] + 1;q.push(make_pair(x, y));}}}return dist;}
};

2、1020. 飞地的数量

 

思路:通过广度优先搜索(BFS)来标记所有可以到达边界的陆地单元格,最后统计未被标记的陆地单元格数量。

  1. 初始化变量:首先,初始化一个队列q和一个vis(visited)数组来记录已访问的单元格。vis数组的大小和原始网格grid一样,用于标记是否已经访问过对应的单元格。

  2. 边界单元格入队:遍历网格的所有边界单元格(即位于第一行、最后一行、第一列、最后一列的单元格)。对于每一个为陆地(值为1)的边界单元格,将其加入队列q中,并在vis数组中标记为已访问。

  3. 广度优先搜索:进行BFS遍历。从队列中取出一个单元格,然后检查它的四个相邻单元格(上、下、左、右)。对于每一个未访问过且为陆地的相邻单元格,将其加入队列q中,并在vis数组中标记为已访问。这一过程不断重复,直到队列为空。

  4. 计数未访问的陆地单元格:经过上述步骤,所有能够到达边界的陆地单元格都被标记为已访问。最后,遍历整个网格,统计所有未被访问过的陆地单元格。这些就是无法到达边界的陆地单元格。

  5. 返回结果:返回步骤4中统计的未访问陆地单元格的数量作为结果。

通过这个方法,我们能够有效地找出所有无法通过任意次移动到达边界的陆地单元格,并计算它们的总数。这种方法的关键在于使用BFS来探索和标记所有可以直接或间接到达边界的陆地单元格,从而区分哪些陆地单元格是完全被包围的。

class Solution {
public:int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};int numEnclaves(vector<vector<int>>& grid) {int m = grid.size(), n = grid[0].size();vector<vector<bool>> vis(m, vector<bool>(n, false));queue<pair<int, int>> q;for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (i == 0 || i == m - 1 || j == 0 || j == n - 1) {if (grid[i][j] == 1) {q.push(make_pair(i, j));vis[i][j] = true;}}}}while (q.size()) {auto a = q.front();q.pop();for (int i = 0; i < 4; i++) {int x = dx[i] + a.first, y = dy[i] + a.second;if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 &&!vis[x][y]) {vis[x][y] = true;q.push(make_pair(x, y));}}}int ret = 0;for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (grid[i][j] == 1 && !vis[i][j])ret++;}}return ret;}
};

3、1765. 地图中的最高点

思路:广度优先搜索是从一组起始点开始(在这个场景中是所有水域格子),然后逐层向外扩散到所有可达的陆地格子,为每个陆地格子分配一个高度值,这个值比其相邻的水域或已处理的陆地格子的高度值大1。

具体步骤如下:

  1. 初始化

    • 创建一个与输入矩阵 isWater 大小相同的矩阵 dist,用于存储每个格子的高度。初始时,所有格子的高度设置为 -1(表示未处理)。
    • 创建一个队列 q,用于执行广度优先搜索。
  2. 处理水域格子

    • 遍历整个 isWater 矩阵,找到所有水域格子(isWater[i][j] == 1的格子)。
    • 将这些水域格子的高度在 dist 矩阵中设置为 0,并将它们加入队列 q(表示这些格子是搜索的起点)。
  3. 广度优先搜索

    • 当队列 q 不为空时,从队列中移除一个格子,对于这个格子的每一个相邻的四个方向(北、南、东、西),执行以下步骤:
      • 计算相邻格子的坐标 (x, y)
      • 检查 (x, y) 是否在矩阵范围内且该格子的高度是否未被设置(即 dist[x][y] == -1)。
      • 如果满足条件,将该格子的高度设置为当前格子的高度加1(dist[x][y] = dist[a.first][a.second] + 1),然后将 (x, y) 加入队列 q

通过以上步骤,每个水域格子周围的陆地格子首先被设置为高度1,然后这些陆地格子的周围陆地格子被设置为高度2,依此类推。这个过程一直持续,直到所有可达的陆地格子都被分配了一个高度值。

最终,dist 矩阵包含了每个格子的高度,这就是算法的输出。

class Solution {
public:int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};vector<vector<int>> highestPeak(vector<vector<int>>& isWater) {int m = isWater.size(), n = isWater[0].size();vector<vector<int>> dist(m, vector<int>(n, -1));queue<pair<int, int>> q;for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (isWater[i][j]) {dist[i][j] = 0;q.push(make_pair(i, j));}}}while (q.size()) {auto a = q.front();q.pop();for (int i = 0; i < 4; i++) {int x = a.first + dx[i], y = a.second + dy[i];if (x >= 0 && x < m && y >= 0 && y < n && dist[x][y] == -1) {dist[x][y] = dist[a.first][a.second] + 1;q.push(make_pair(x, y));}}}return dist;}
};

4、1162. 地图分析

 思路:多源 bfs直接上手

class Solution {
public:int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};int maxDistance(vector<vector<int>>& grid) {int m = grid.size(), n = grid[0].size();vector<vector<int>> dist(m, vector<int>(n, -1));queue<pair<int, int>> q;for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (grid[i][j] == 1) {dist[i][j] = 0;q.push(make_pair(i, j));}}}int ret = -1;while (q.size()) {auto a = q.front();q.pop();for (int i = 0; i < 4; i++) {int x = a.first + dx[i], y = a.second + dy[i];if (x >= 0 && x < m && y >= 0 && y < n && dist[x][y] == -1) {dist[x][y] = dist[a.first][a.second] + 1;q.push(make_pair(x, y));ret = max(ret, dist[x][y]);}}}return ret;}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/749372.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【模拟string函数的实现】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 模拟string函数的实现 浅拷贝 深拷贝 vs和g下string结构的说明 总结 前言 模拟string函数的实现 浅拷贝 深拷贝 总结 前言 世上有两种耀眼的光芒&#…

Java面向对象案例之描述专业和学生(4)

类的方法图 学生类&#xff1a; 属性&#xff1a;学号&#xff0c;姓名&#xff0c;年龄&#xff0c;所学习的专业方法&#xff1a;学习的方法&#xff0c;描述学习状态。描述内容包括姓名、学号、年龄、所学习的专业信息 专业类&#xff1a; 属性&#xff1a;专业编号&#xf…

2024年【天津市安全员C证】考试资料及天津市安全员C证考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 天津市安全员C证考试资料根据新天津市安全员C证考试大纲要求&#xff0c;安全生产模拟考试一点通将天津市安全员C证模拟考试试题进行汇编&#xff0c;组成一套天津市安全员C证全真模拟考试试题&#xff0c;学员可通过…

uniapp——第2篇:编写vue语法

前提&#xff0c;建议先学会前端几大基础&#xff1a;HTML、CSS、JS、Ajax&#xff0c;还有一定要会Vue!&#xff08;Vue2\Vue3&#xff09;都要会&#xff01;&#xff01;&#xff01;不然不好懂 一、去哪写&#xff1f; 就在【pages】的你的人一个页面文件夹里的【.vue】文…

多站合一的音乐搜索下载助手PHP源码l亲测

源码获取方式 回复&#xff1a;031601 搭建教程&#xff1a; 将源码下载上传至宝塔面板&#xff0c;直接运行即可~ 说明&#xff1a; 该源码进行测试&#xff0c;测试成功源码无加密优化相关其他采集问题。

langchain+chatglm3+BGE+Faiss Linux环境安装依赖

前言 本篇默认读者已经看过之前windows版本&#xff0c;代码就不赘述&#xff0c;本次讲述是linux环境配置 超短代码实现&#xff01;&#xff01;基于langchainchatglm3BGEFaiss创建拥有自己知识库的大语言模型(准智能体)本人python版本3.11.0&#xff08;windows环境篇&…

Go微服务实战——服务的配置获取(nacos做配置中心)

nacos做配置中心 demo仓库 docker安装nacos docker pull nacos/nacos-server 使用docker每次需要sudo可以执行如下命令 sudo groupadd docker #添加用户组 sudo gpasswd -a username docker #将当前用户添加至用户组-d就是删除该组中的用户 newgrp docker…

L1-070 吃火锅分数 15

我们老师的话说就是&#xff0c;你学长睡了四年的床板子你不收拾收拾就往上躺着睡觉吗&#xff1f;&#xff1f;&#xff1f;一定要记得用到计数变量时首先要赋初值0或者其他&#xff0c;按题目要求来。 用 输入样例 1&#xff1a; Hello! are you there? wantta chi1 huo3…

排序链表的三种写法

题目链接&#xff1a;https://leetcode.cn/problems/sort-list/?envTypestudy-plan-v2&envIdtop-100-liked 第一种&#xff0c;插入排序&#xff0c;会超时 class Solution {public ListNode sortList(ListNode head) {//插入排序&#xff0c;用较为简单的方式解决ListNo…

程序人生——Java泛型和反射的使用建议

目录 引出泛型和反射建议93&#xff1a;Java的泛型是类型擦除的建议94&#xff1a;不能初始化泛型参数和数组建议95&#xff1a;强制声明泛型的实际类型 建议96&#xff1a;不同的场景使用不同的泛型通配符建议97&#xff1a;警惕泛型是不能协变和逆变的 建议98&#xff1a;建议…

C++:类之六脉神剑——默认成员函数

个人主页&#xff1a;日刷百题 系列专栏&#xff1a;〖C/C小游戏〗〖Linux〗〖数据结构〗 〖C语言〗 &#x1f30e;欢迎各位→点赞&#x1f44d;收藏⭐️留言&#x1f4dd; ​ ​ 一、默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为 空类 。 空类中真的什么都…

【Poi-tl Documentation】自定义占位符来设置图片大小

前置说明&#xff1a; <dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.12.1</version> </dependency>模板文件&#xff1a; image_test.docx package run.siyuan.poi.tl.policy;imp…

双路控制比例方向阀放大器

该模块比例放大器用于控制一个带有两个螺线管的比例方向控制阀或一个/两个独立的比例压力阀或比例节流阀&#xff0c;每个阀带有一个或二个螺线管。 各种可调参数允许对相应阀门的最佳适应。单路双路四路控制&#xff0c;供电24VDC&#xff0c;输入指令兼容多种可选&#xff0c…

代码随想录训练营Day25:● 216.组合总和III ● 17.电话号码的字母组合

216.组合总和III 题目链接 https://leetcode.cn/problems/combination-sum-iii/description/ 题目描述 思路 自己写的效率会慢一些&#xff0c;而且没有用到剪枝 class Solution {List<List<Integer>> list new ArrayList<>();List<Integer> lis…

识别和定位 - 实现工业自动化及生产数字化,推动现代工业4.0

工业4.0的定义 工业 4.0 是指将智能数字化技术集成到制造和工业流程&#xff0c;包括工业物联网网络、人工智能、大数据、机器人和自动化等一系列技术。工业 4.0 能帮助企业实现智能制造&#xff0c;建立智能工厂&#xff0c;目标是提高生产力、效率和灵活性&#xff0c;同时在…

虹科Pico汽车示波器 | 免拆诊断案例 | 2015 款路虎神行者车熄火后散热风扇依旧高速运转

一、故障现象 一辆2015款路虎神行者车&#xff0c;搭载2.2 L发动机&#xff0c;累计行驶里程约为16万km。车主反映&#xff0c;车辆熄火后&#xff0c;散热风扇依旧高速运转&#xff0c;且无法停止。 二、故障诊断 接车后首先试车&#xff0c;故障现象的确存在。使用故障检…

软件测试之学习测试用例的设计(等价类法、边界值法、错误猜测法、场景法、因果图法、正交法)

1. 测试用例的概念 软件测试人员向被测试系统提供的一组数据的集合&#xff0c;包括 测试环境、测试步骤、测试数据、预期结果 2. 为什么在测试前要设计测试用例 测试用例是执行测试的依据 在回归测试的时候可以进行复用 是自动化测试编写测试脚本的依据 衡量需求的覆盖率…

性能测试工具——wrk的安装与使用

前言 想和大家来聊聊性能测试&#xff0c;聊到了性能测试必须要说的是性能测试中的工具&#xff0c;在这些工具中我今天主要给大家介绍wrk。 ​介绍 wrk是一款开源的性能测试工具 &#xff0c;简单易用&#xff0c;没有Load Runner那么复杂&#xff0c;他和 apache benchmar…

多种智能搜索算法可视化还原 3D 魔方

一、写在前面 许久没有写图形化界面的程序了&#xff0c;最近学习了一些经典的盲目搜索算法与智能搜索算法&#xff0c;正好拿来还原三阶魔方&#xff01;试试手&#xff01; 提前声明 我不是专业搞人工智能的&#xff0c;理论或者实现过程有些许错误也很正常&#xff0c;评论…

YOLOv5_seg-Openvino和ONNXRuntime推理【CPU】

纯检测系列&#xff1a; YOLOv5-Openvino和ONNXRuntime推理【CPU】 YOLOv6-Openvino和ONNXRuntime推理【CPU】 YOLOv8-Openvino和ONNXRuntime推理【CPU】 YOLOv7-Openvino和ONNXRuntime推理【CPU】 YOLOv9-Openvino和ONNXRuntime推理【CPU】 跟踪系列&#xff1a; YOLOv5/6/7-O…