多源 BFS 详解

目录

一、多源与单源的区别

二、例题练习

2.1 例题1:01 矩阵

2.2 例题2:飞地的数量

2.3 例题3:地图中的最高点 

2.4 例题4:地图分析


一、多源与单源的区别

单源最短路问题如何解决已经在上篇博客给出BFS 解决最短路问题,如果还没学习单源的建议先学习,因为多源就是在单源的基础上进行一些改动即可,即把多个源点一起放入队列中。

• 注意:

多源 BFS 只能用来解决边权为 1 (其实只要边权相等即可,可以转化为边权 1 来解决)的多源最短路问题。如果是边权不相等的情况那么就要使用到图论里面的 Floyd-Warshall 算法,这个后续会写到。

那么该如何解决多源 BFS 问题呢?

解法1:暴力,直接把多源最短路问题转化为若干个单源最短路问题,这个大概率是会超时的,因为重复查找的次数非常多。

解法2:把所有的源点当成一个 “超级源点”,那么问题就变成了单一的单源最短路问题。

如何证明正确性呢? 

理性:严格的证明,这些在一些算法书上能够找到,比较麻烦,文章主要写,如何来做题。故我们就感性的理解一下。

感性:就好比如下图这些性能相同的汽车(把汽车看成开始的源点),如果采用单源最短路的解决思路就是一辆一辆车启动,最后比较谁先到终点。如果采用多源最短路的解题思路就是把这些车一起启动,谁先到终点,就是最短路。这里可能有的友友会问,这样和单源最短路的时间复杂度不是一样的嘛?其实当在同一条路上如果有节点在前面,那么后面的节点就可以直接舍去,因为绝对不可能是最短路。

二、例题练习

2.1 例题1:01 矩阵

• 题目链接:01 矩阵

• 问题描述:

给定一个由 0 和 1 组成的矩阵 mat ,请输出一个大小相同的矩阵,其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。

两个相邻元素间的距离为 1 。

• 解题思路:

如果采用单源最短路(一个位置一个位置的去求)的话会超时(替大家试过了),正确的解法多源 BFS + 正难则反(填表更快),把所有的 0 当成起点,1当作终点(终点可以有多个)。找到一个 1 且是没有被遍历过的就可以把路径数直接填入,因为绝对没有比这个更小的路径了。

• 代码编写:

直接把最开始创建的数组都初始化成 -1 ,这样就不用创建一个 vis 表来标记已经走过的节点。且路径数可以直接在原来的路径数上 + 1 即可,一举两得。具体代码如下:

class Solution {int[] dx = {0,0,1,-1};int[] dy = {1,-1,0,0};public int[][] updateMatrix(int[][] mat) {//1.把所有为0的元素存入队列int n = mat.length;int m = mat[0].length;//2.创建 dest 数组//3.dest初始化为 - 1int[][] dest = new int[n][m];for(int i = 0;i < n;i++){Arrays.fill(dest[i],-1);}Queue<int[]> q = new LinkedList<>();for(int i = 0;i < n;i++){for(int j = 0;j < m;j++){if(mat[i][j] == 0){dest[i][j] = 0;q.add(new int[]{i,j});}}}//4.bfswhile(!q.isEmpty()){int[] tmp = q.poll();int a = tmp[0],b = tmp[1];for(int k = 0;k < 4;k++){int x = a + dx[k];int y = b + dy[k];if(x >= 0 && x < n && y >= 0 && y < m && dest[x][y] == -1){if(mat[x][y] == 1){//5.在原来的基础上直接 + 1dest[x][y] = dest[a][b] + 1;}q.add(new int[]{x,y});}}}return dest;}
}

2.2 例题2:飞地的数量

• 题目链接:飞地的数量

• 问题描述:

给你一个大小为 m x n 的二进制矩阵 grid ,其中 0 表示一个海洋单元格、1 表示一个陆地单元格。

一次 移动 是指从一个陆地单元格走到另一个相邻(上、下、左、右)的陆地单元格或跨过 grid 的边界。

返回网格中 无法 在任意次数的移动中离开网格边界的陆地单元格的数量。

• 解题思路:

正难则反: 从边上的 1 开始搜索,把与边上 1 相连的联通区域全部标记⼀下,然后再遍历⼀遍矩阵,看看哪些位置的 1 没有被标记即可,标记的时候,可以用多源 bfs 解决(这题单源或者 DFS都行)。

• 代码编写:

class Solution {int n,m;int[] dx = {0,0,1,-1};int[] dy = {1,-1,0,0};public int numEnclaves(int[][] grid) {n = grid.length;m = grid[0].length;//1.拿所有边界的1进行一次bfs标记Queue<int[]> q = new LinkedList<>();for(int i = 0;i < n;i++){for(int j = 0;j < m;j++){if(i == 0 || i == n - 1 || j == 0 || j == m - 1){//这么写比较快且不容易出错if(grid[i][j] == 1){q.add(new int[]{i,j});}}}}//直接改为2即可while(!q.isEmpty()){int size = q.size();for(int i = 0;i < size;i++){int[] tmp = q.poll();int a = tmp[0],b = tmp[1];grid[a][b] = 2;for(int k = 0;k < 4;k++){int x = a + dx[k];int y = b + dy[k];if(x >= 0 && x < n && y >= 0 && y < m && grid[x][y] == 1){q.add(new int[]{x,y});grid[x][y] = 2;}}}}//2.最后遍历如果为 1 且未被标记的话ret++int ret = 0;//最后的结果for(int i = 0;i < n;i++){for(int j = 0;j < m;j++){if(grid[i][j] == 1){ret++;}}}//3.返回 retreturn ret;}
}

2.3 例题3:地图中的最高点 

• 题目链接:地图中的最高点

• 问题描述:

给你一个大小为 m x n 的整数矩阵 isWater ,它代表了一个由 陆地 和 水域 单元格组成的地图。

  • 如果 isWater[i][j] == 0 ,格子 (i, j) 是一个 陆地 格子。
  • 如果 isWater[i][j] == 1 ,格子 (i, j) 是一个 水域 格子。

你需要按照如下规则给每个单元格安排高度:

  • 每个格子的高度都必须是非负的。
  • 如果一个格子是 水域 ,那么它的高度必须为 0 。
  • 任意相邻的格子高度差 至多 为 1 。当两个格子在正东、南、西、北方向上相互紧挨着,就称它们为相邻的格子。(也就是说它们有一条公共边)

找到一种安排高度的方案,使得矩阵中的最高高度值 最大 。

请你返回一个大小为 m x n 的整数矩阵 height ,其中 height[i][j] 是格子 (i, j) 的高度。如果有多种解法,请返回 任意一个 。

• 解题思路:

01矩阵的变型题,直接用多源 bfs 解决即可。任意相邻的格子高度差 至多 为 1,这个条件非常重要,因为有这个条件我们才能确定这题其实是用最短路的思路来解决。具体就是把所有水域的格子添加到队列中,一层一层遍历即可。

• 代码编写:

class Solution {int[] dx = {0,0,1,-1};int[] dy = {1,-1,0,0};public int[][] highestPeak(int[][] isWater) {//多源 bfsint n = isWater.length;int m = isWater[0].length;int[][] ans = new int[n][m];//3.把返回数组初始化为 -1for(int i = 0;i < n;i++){Arrays.fill(ans[i],-1);}//1.找到所有的值为 1 的加入 bfsQueue<int[]> q = new LinkedList<>();for(int i = 0;i < n;i++){for(int j = 0;j < m;j++){if(isWater[i][j] == 1){ans[i][j] = 0;q.add(new int[]{i,j});}}}while(!q.isEmpty()){int size = q.size();for(int i = 0;i < size;i++){int[] tmp = q.poll();int a = tmp[0],b = tmp[1];//这个地方不用再填值了for(int k = 0;k < 4;k++){int x = a + dx[k];int y = b + dy[k];if(x >= 0 && x < n && y >= 0 && y < m && ans[x][y] == -1 && isWater[x][y] == 0){ans[x][y] = ans[a][b] + 1;//直接在原来的数值上 + 1 即可//不用再来一个timeq.add(new int[]{x,y});}}}}//4.返回答案return ans;}
}

2.4 例题4:地图分析

• 题目链接:地图分析

• 问题描述:

你现在手里有一份大小为 n x n 的 网格 grid,上面的每个 单元格 都用 0 和 1 标记好了。其中 0 代表海洋,1 代表陆地。

请你找出一个海洋单元格,这个海洋单元格到离它最近的陆地单元格的距离是最大的,并返回该距离。如果网格上只有陆地或者海洋,请返回 -1

我们这里说的距离是「曼哈顿距离」( Manhattan Distance):(x0, y0) 和 (x1, y1) 这两个单元格之间的距离是 |x0 - x1| + |y0 - y1| 。

• 解题思路:

正难则反,把所有 1 的节点都进队,这样一次就可以把所有的 0 都填好(路径数)。和上面几题都差不多,多源 BFS 代码编写倒是不难,主要是要先转化一下,怎么把那么多节点变成 “超级源点”。

• 代码编写:

class Solution {int[] dx = {0,0,1,-1};int[] dy = {1,-1,0,0};public int maxDistance(int[][] grid) {//多源 bfsint n = grid.length;int m = grid[0].length;boolean[][] vis = new boolean[n][m];//1.把 1 进 bfsQueue<int[]> q = new LinkedList<>();for(int i = 0;i < n;i++){for(int j = 0;j < m;j++){if(grid[i][j] == 1){q.add(new int[]{i,j});}}}if(q.size() == 0 || q.size() == (n * m)){return -1;}int time = 0;//2.time计数while(!q.isEmpty()){int size = q.size();time++;for(int i = 0;i < size;i++){int[] tmp = q.poll();int a = tmp[0],b = tmp[1];vis[a][b] = true;for(int k = 0;k < 4;k++){int x = a + dx[k],y = b + dy[k];if(x >= 0 && x < n && y >= 0 && y < m && !vis[x][y] && grid[x][y] == 0){q.add(new int[]{x,y});//3.vis 去重vis[x][y] = true;}}}}return time - 1;}
}

• 小结:和单源 BFS 找最短路的模板基本一样,只要多加练习,代码编写是很简单的,重要的是思路,哪些题目可以使用多源 BFS 来解决,这个就需要多做题了👍👍👍。

结语:

其实写博客不仅仅是为了教大家,同时这也有利于我巩固知识点,和做一个学习的总结,由于作者水平有限,对文章有任何问题还请指出,非常感谢。如果大家有所收获的话还请不要吝啬你们的点赞收藏和关注,这可以激励我写出更加优秀的文章。

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

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

相关文章

最新版ERP进销存网络多仓版WEB源码

安装说明 环境要求&#xff1a; PHP5.6MYSQL5.6 1.恢复数据库.sql数据 2.配置sql参数连接路径&#xff1a;application\config\database.php 3.前台登录用户名&#xff1a;admin 密码&#xff1a;admin 源码免费下载地址抄笔记 (chaobiji.cn)

Spring Data JPA与Hibernate的关系是什么?

Spring Data JPA 和 Hibernate 的关系可以用术语“抽象层”和“实现”来描述。在这种关系中&#xff0c;Spring Data JPA 表现为一个更高级别的抽象层&#xff0c;而 Hibernate 是这一层下面的一个具体实现。 Hibernate Hibernate 是一个非常流行的 Java 持久化框架。它提供了…

解决sd-webui中rembg插件使用报错问题

stable-diffusion-webui-rembg是我非常喜欢的sd-webui插件&#xff0c;PS抠图手残党的福音&#xff0c;一键抠图太爽啦。对于主体明确线条简单的图片&#xff08;如汽车、服饰简洁的人像等&#xff09;效果相当好&#xff1b;即便对于毛茸茸的对象&#xff08;如动物&#xff0…

C语言选择排序编程:深入剖析与实战指南

C语言选择排序编程&#xff1a;深入剖析与实战指南 在C语言编程中&#xff0c;选择排序是一种简单直观的排序算法。本文将通过四个方面、五个方面、六个方面和七个方面&#xff0c;深入剖析选择排序的原理、实现过程以及注意事项&#xff0c;帮助读者更好地掌握这一算法&#…

Elasticsearch安装与配置:快速搭建本地环境

Elasticsearch&#xff0c;作为当下最流行的开源搜索引擎和数据分析工具之一&#xff0c;其强大的全文搜索能力和丰富的数据分析功能&#xff0c;吸引了众多开发者和数据分析师的关注。本文将指导你如何快速在本地搭建Elasticsearch环境&#xff0c;以便你能够立即开始探索其强…

编译器屏障概述

文章目录 1. 前言2. 编译器内存屏障2.1 编译器内存访问重排序规则2.2 编译器屏障的几种形式2.2.1 显式编译器屏障2.2.2 隐式编译器屏障2.2.3 硬件内存屏障充当编译屏障2.2.4 编程语言内存模型提供的编译屏障 2.3 编译器内存屏障实例2.3.1 Linux spinlock 3. 结语4. 参考资料 1.…

Minio启动脚本-Windows版

MinIO 是一种高性能、S3 兼容的对象存储。 它专为大规模 AI/ML、数据湖和数据库工作负载而构建,并且它是由软件定义的存储。 不需要购买任何专有硬件,就可以在云上和普通硬件上拥有分布式对象存储。 MinIO拥有开源 GNU AGPL v3 和商业企业许可证的双重许可。 ——摘自…

MySQL之创建高性能的索引(十二)

创建高性能的索引 支持多种过滤条件 这些索引将满足大部分最常见的搜索查询&#xff0c;但是如何为一些生僻的搜索条件(比如has_pictures、eye_color、hair_colr和education)来设计索引呢&#xff1f;这些列的选择性搞&#xff0c;使用也不频繁&#xff0c;可以选择忽略它们&…

云计算和雾计算

雾计算作为传统集中式数据存储系统&#xff08;云&#xff09;和边缘设备之间的中间层。雾扩展了云&#xff0c;使计算和数据存储更接近边缘。雾由多个节点&#xff08;雾节点&#xff09;组成&#xff0c;并创建一个本地网络&#xff0c;使其成为一个去中心化的生态系统——雾…

如何创建一个Angular项目(超简单)

1、安装Node.js&#xff08;官网Node.js下载&#xff09; 2、运行node -v和npm -v两条命令&#xff08;检验是否下载成功Node.js&#xff09; 3、npm i -g cnpm --registryhttps://registry.npmmirror.com&#xff08;用npm安装cnpm&#xff0c;将镜像源设置为国内镜像源&…

ROS2 (python)构造服务端和客户端

要注意&#xff1a;服务端和客户端的名字要统一 什么是线程死锁 A需要等B把装满水的桶放下 才能把水桶提走 B需要等A把水桶提走才能把自己的装满 假设A和B都要站在位置C工作 A&#xff1a;站在工位C将小桶水倒进大桶里 B&#xff1a;从C位置将装满水的大桶拎走 那么假设时刻…

Next前端是什么

Next前端是什么 在前端开发的浩瀚星空中&#xff0c;Next前端如同一颗璀璨的明星&#xff0c;吸引着无数开发者的目光。那么&#xff0c;Next前端究竟是什么呢&#xff1f;它为何能在前端领域掀起如此波澜&#xff1f;接下来&#xff0c;我们将从四个方面、五个方面、六个方面…

制作一个简单HTML旅游网站(HTML+CSS+JS)云南旅游网页设计与实现5个页面

一、&#x1f468;‍&#x1f393;网站题目 旅游&#xff0c;当地特色&#xff0c;历史文化&#xff0c;特色小吃等网站的设计与制作。 二、✍️网站描述 云南旅游主题的网页 一共七个个页面 - 旅游网页使用html css js制作 有banana图 - 页面可以相互跳转 包含表单 三级页面…

Laravel 富文本内容

Laravel 获取富文本的纯文本内容-CSDN博客 Laravel 富文本内容里面的图片添加前缀URL-CSDN博客 Laravel 富文本图片的style样式删除-CSDN博客. 富文本字体font-famly删除 $data preg_replace(/(<[^>])style["\][^"\]*font-family:[^"\]*["\]([^&…

Shopee爆款打造核心运营方法,下一个大卖就是你

课程下载&#xff1a;Shopee爆款打造核心运营方法&#xff0c;下一个大卖就是你-课程网盘链接提取码下载.txt资源-CSDN文库 更多资源下载&#xff1a;关注我。 课程内容&#xff1a; 001.1-爆款产品的选择,mp4 002.2-依据宗教信仰和消费禁忌选品.mp4 003.3-刻画消费者画像…

C++设计模式-桥接模式

运行在VS2022&#xff0c;x86&#xff0c;Debug下。 29. 桥接模式 桥接模式将抽象与实现分离&#xff0c;使二者可以独立地变化。 应用&#xff1a;如在游戏开发中&#xff0c;多个角色和多个武器交叉组合时。可以使用桥接模式&#xff0c;定义角色抽象类&#xff0c;武器抽象…

如何跨渠道分析销售数据 - 7年制造业销售经验小结

如何跨渠道分析销售数据 - 7年制造业销售经验小结&#xff08;1&#xff09; 【前言】 在我过去7年销售工作生涯中&#xff0c;从第一年成为公司销冠后&#xff0c;我当时的确自满的一段时间&#xff0c;认为自己很了不起。但是第一年的销售业绩并没有拿到提成&#xff0c;最…

2024-06-02 问AI: 在大语言模型中,什么是multi agent?

文心一言 在大语言模型中&#xff0c;Multi-Agent&#xff08;多智能体&#xff09;是指由多个具有自主决策和交互能力的智能体&#xff08;Agent&#xff09;组成的系统。这些智能体能够相互协作、竞争或协商&#xff0c;以完成共同或各自的任务。以下是关于Multi-Agent在大语…

爱情的短视频短片:四川京之华锦信息技术公司

爱情的短视频短片&#xff1a;情感瞬间的浓缩与绽放 在数字化时代&#xff0c;短视频以其短小精悍、直击人心的特点&#xff0c;迅速占领了互联网的高地。而在这些纷繁复杂的短视频内容中&#xff0c;关于爱情的短视频短片更是以其独特的魅力&#xff0c;吸引了无数观众的目光…

【U-Net验证】逐元素乘积将特征投射到极高维隐式特征空间的能力

写在前面&#xff1a;本博客仅作记录学习之用&#xff0c;部分图片来自网络&#xff0c;如需使用请注明出处&#xff0c;同时如有侵犯您的权益&#xff0c;请联系删除&#xff01; 文章目录 前言网络结构编码结构解码结构代码 实验实验设置w/o-ReLU的性能比较with-ReLU的性能比…