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

算法:BFS 解决多源最短路问题

目录

多源最短路

题目一:矩阵

题目二:飞地的数量

题目三:地图中的最高点

题目四:地图分析


多源最短路

首先想要知道多源最短路,就先要明白单源最短路,bfs解决单源最短路问题前面学习过,单源最短路就是只有一个起点,到终点的最短路径

多源最短路就是有若干个起点,到终点的最短路径

多源bfs就是使用bfs解决多源最短路问题

这里再强调一下,能够使用bfs,前提必须是边权为1的问题

多源最短路问题的解决方法:

解法一:暴力枚举

将每一个起点都进行bfs,每个起点都会获得一个结果,得到的这些结果中最小的那一个就是题目所要求的

这种解答大概率是会超时的,所以学习下面的解法二

解法二:把所有的源点当成一个源点

此时问题就变为了单一的单源最短路问题了

在单源最短路问题中,我们是把一个起点加入队列,再一层一层往外扩展

而多源最短路问题中,我们是把所有起点加入队列,再一层一层往外扩展

其实代码都是差不多的,区别就是刚开始的队列加入的起点数目不同


题目一:01矩阵

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

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

示例 1:

输入:mat = [[0,0,0],[0,1,0],[0,0,0]]
输出:[[0,0,0],[0,1,0],[0,0,0]]

示例 2:

输入:mat = [[0,0,0],[0,1,0],[1,1,1]]
输出:[[0,0,0],[0,1,0],[1,2,1]]

这道题的题意就是求矩阵中每一个位置的元素的值,每个位置的值是距离最近的0的距离,如果本身就是0,那么距离就是0

解法一:每个位置挨个求

在这种解法中,二维数组的每一个位置依次求离最近的0的距离,很显然是会超时的,所以这种解法就排除了

解法二:多源BFS + 正难则反

因为采用的多源bfs的策略,最初的想法就是将所有的1当做一个起点,去找0,得到最小的距离,但是当找到0后,我们无法得知当前的找到的最短距离是哪个位置的1,所以这种策略是不对的

那么正难则反,我们可以将所有的0当做一个起点,去找1,这样找到的结果和上面也是一样的

那么此时当找到1后,就可以将当前的最短步数直接更新到1的位置上即可,

所以分为下面两步:

1、把所有的0加入到队列中

遍历过程中,所有0位置的数据可以直接更新为0,因为自己本身就是0,距离也就是0

2、一层一层向外扩展

扩展过程中需要注意,已经赋过值的位置就不需要重复赋值了,因为第一次赋值的一定是最短的距离

细节问题:

在前面的单源最短路问题中,我们使用了三个元素来解决,分别是:
记录是否重复出现的bool数组vis
每一次出队列的个数sz
记录扩展了step层,这里的step就是最短路径了

而多源最短路问题,不需要上面的三个元素,只需要一个dist数组即可

因为初始化时,将dist中的值全部初始化为-1,然后将原始值是0的继续改为0,此时再bfs过程中,只要是-1的才改变它的值,这里就不需要使用vis来标记了

并且我们变化是从(a,b)变为(x,y),当走到(x,y)后,(x,y)的值就是(a,b)的值+1,所以这里也就不需要之前的sz和step了,直接一个dist数组就能解决,dist数组为-1就表示还没有被搜索过,dist不为-1,就表示当前位置的最短距离

当然了此题也是可以使用这三个全局变量,这里只是说明一下,可以更简便的解题

代码如下:

class Solution 
{
public:int dx[4] = {0,0,-1,1};int dy[4] = {-1,1,0,0};vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {int m = mat.size(), n = mat[0].size();vector<vector<int>> dist(m, vector<int>(n, -1));queue<pair<int, int>> q;// 将mat中的0的位置dist该位置也改为0,并将坐标都入队列for(int i = 0; i < m; i++){for(int j = 0; j < n; j++){if(mat[i][j] == 0){dist[i][j] = 0;q.push({i, j});}}}// 一层一层往外扩while(!q.empty()){// 不需要计算sz,因为dist的值就可以表示走了几步auto [a, b] = q.front();q.pop();int tmp = dist[a][b];for(int k = 0; k < 4; k++){int x = a + dx[k];int y = b + dy[k];if(x >= 0 && x < m && y >= 0 && y < n && dist[x][y] == -1){dist[x][y] = tmp + 1;q.push({x, y});}}}return dist; }
};

题目二:飞地的数量

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

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

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

示例 1:

输入:grid = [[0,0,0,0],[1,0,1,0],[0,1,1,0],[0,0,0,0]]
输出:3
解释:有三个 1 被 0 包围。一个 1 没有被包围,因为它在边界上。

示例 2:

输入:grid = [[0,1,1,0],[0,0,1,0],[0,0,1,0],[0,0,0,0]]
输出:0
解释:所有 1 都在边界上或可以到达边界。

解法一:暴力解法

在遍历的过程中,找到每一个1,每一个1都去判断,是否能够到达边界

这种解法一定会超时,但是也可以做优化

即找到某一个1时,如果发生这个1能够到达边界,那么此时再遍历一遍,将这个遍历过程中的所有1都做一下标记, 下次就不需要遍历这些做过标记的1了,这种优化可以做到不超时,但是还是有些麻烦的,因为需要bfs两次,下面看解法二

解法二:正难则反

从里面找1到边界需要考虑的事情非常多,但是我可以从边界的所有1开始向里面搜索,此时搜索到的1就一定是可以到达边界的

这种解法使用bfs时,就可以采用多源bfs的方法,将边界所有的1全部添加进队列中,就可以将所有的满足条件的1全部遍历到,最后再找不满足的条件的1的个数即可

代码如下:

class Solution 
{
public:typedef pair<int, int> PII; int dx[4] = {0,0,-1,1};int dy[4] = {-1,1,0,0};bool vis[501][501];int numEnclaves(vector<vector<int>>& g) {int m = g.size(), n = g[0].size();queue<PII> q;// 将边界的1加入队列中for(int i = 0; i < m; i++)for(int j = 0; j < n; j++)if(g[i][j] == 1 && (i == 0 || i == m - 1 || j == 0 || j == n - 1)){q.push({i, j});vis[i][j] = true;}// 多源 bfswhile(!q.empty()){auto [a, b] = q.front();q.pop();for(int k = 0; k < 4; k++){int x = a + dx[k];int y = b + dy[k];if(x >= 0 && x < m && y >= 0 && y < n && g[x][y] == 1 && vis[x][y] == false){q.push({x, y});vis[x][y] = true;}}}// 统计结果int ret = 0;for(int i = 0; i < m; i++)for(int j = 0; j < n; j++)if(g[i][j] == 1 && vis[i][j] == false)ret++;return ret;}
};

题目三:地图中的最高点

给你一个大小为 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) 的高度。如果有多种解法,请返回 任意一个 。

示例 1:

输入:isWater = [[0,1],[0,0]]
输出:[[1,0],[2,1]]
解释:上图展示了给各个格子安排的高度。
蓝色格子是水域格,绿色格子是陆地格。

示例 2:

输入:isWater = [[0,0,1],[1,0,0],[0,0,0]]
输出:[[1,1,0],[0,1,1],[1,2,2]]
解释:所有安排方案中,最高可行高度为 2 。
任意安排方案中,只要最高高度为 2 且符合上述规则的,都为可行方案。

这道题的题目描述比较长,其实理解一下就是:

原始矩阵的0表示陆地,1表示水域,需要我们返回一个新矩阵,新矩阵的要求如下:

①原始为水域的位置新矩阵要为0
②其余的位置,每次扩展都可以高度加1
③求整个矩阵的最高高度值

理解完题意,可以看出来,也就是多源bfs,从0位置开始扩展,每次扩展到其他位置时,都+1即可,非常简单

代码如下:

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 m = isWater.size(), n = isWater[0].size();vector<vector<int>> height(m, vector<int>(n, -1));queue<PII> q;// 将所有源点(水域)加入队列for(int i = 0; i < m; i++)for(int j = 0; j < n; j++)if(isWater[i][j] == 1){height[i][j] = 0;q.push({i, j});}// 多源bfswhile(!q.empty()){auto [a, b] = q.front();q.pop();for(int k = 0; k < 4; k++){int x = a + dx[k];int y = b + dy[k];if(x >= 0 && x < m && y >= 0 && y < n && height[x][y] == -1){// 每次的高度是之前高度+1height[x][y] = height[a][b] + 1;q.push({x, y});}}}return height;}
};

题目四:地图分析

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

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

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

示例 1:

输入:grid = [[1,0,1],[0,0,0],[1,0,1]]
输出:2
解释: 
海洋单元格 (1, 1) 和所有陆地单元格之间的距离都达到最大,最大距离为 2。

示例 2:

输入:grid = [[1,0,0],[0,0,0],[0,0,0]]
输出:4
解释: 
海洋单元格 (2, 2) 和所有陆地单元格之间的距离都达到最大,最大距离为 4。

同样,此题也非常简单,简单分析一下:

0表示海洋,1表示陆地,请找到海洋距离最远的陆地,如果整个矩阵只有海洋或是陆地,就返回-1

这道题的解法和前面几乎一模一样, 找0到1的最大距离,这个并不好找

我们同样正难则反,找1到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 m = grid.size(), n = grid[0].size();vector<vector<int>> dist(m, vector<int>(n, -1));queue<PII> 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({i, j});}int ret = -1;while(!q.empty()){auto [a, b] = q.front();q.pop();for(int k = 0; k < 4; k++){int x = a + dx[k];int y = b + dy[k];if(x >= 0 && x < m && y >= 0 && y < n && dist[x][y] == -1){q.push({x, y});dist[x][y] = dist[a][b] + 1;ret = max(ret, dist[x][y]);}}}return ret;}
};

BFS 解决多源最短路问题到此结束

相关文章:

算法:BFS 解决多源最短路问题

目录 多源最短路 题目一&#xff1a;矩阵 题目二&#xff1a;飞地的数量 题目三&#xff1a;地图中的最高点 题目四&#xff1a;地图分析 多源最短路 首先想要知道多源最短路&#xff0c;就先要明白单源最短路&#xff0c;bfs解决单源最短路问题前面学习过&#xff0c;单…...

grep工具的使用

grep [options]…… pattern [file]…… 工作方式&#xff1a; grep 在一个或者多个文件中搜索字符串模板&#xff0c;如果模板中包括空格&#xff0c;需要使用引号引起来&#xff0c;模 板后的所有字符串会被看作是文件名。 工作结果&#xff1a;如果模板搜索成功&#xf…...

Langchain核心模块与实战[9]:RAG检索增强生成[文本向量化、实战ChatDoc智能文档助手]

Langchain核心模块与实战[9]:RAG检索增强生成[文本向量化、实战ChatDoc智能文档助手] 参考文章可以使用国产LLM进行下述项目复现: 初识langchain[1]:Langchain实战教学,利用qwen2.1与GLM-4大模型构建智能解决方案[含Agent、tavily面向AI搜索]langchain[2]:Langchain实战教…...

Java从入门到精通(十五) ~ IO流

晚上好&#xff0c;愿这深深的夜色给你带来安宁&#xff0c;让温馨的夜晚抚平你一天的疲惫&#xff0c;美好的梦想在这个寂静的夜晚悄悄成长。 目录 前言 什么是IO流&#xff1f; IO流的作用&#xff1a; 一、基础流 1. 字节流 1.1 字节输入流 FileInputStream 1.2 字节…...

C Primer Plus 第4章——第二篇

你该逆袭了 第4章&#xff1a;重点摘录 五、scanf( )1、使用 scanf( )(1)转换说明 *(2)转换说明 数字(3)转换说明 hh(4)scanf 中其他的转换说明&#xff0c;不作详细解释&#xff0c;用到的时候再去学习即可 2、从 scanf( ) 角度 看 输入3、格式字符串中的普通字符4、scanf&…...

优化海外用户体验,畅通支付路径!来了解WeTest的本地化支付测试方案

在APP出海的全生命周期中&#xff0c;支付系统的稳定运行是至关重要的一环。随着产品服务覆盖地区的拓展、APP内付费功能的拓展以及不同地区用户对多样化支付渠道的需求增加&#xff0c;出海APP的当地支付体验的优劣直接影响到海外用户的消费决策。 然而海外支付风控升级&#…...

VUE框架面试整理-模板语法

Vue.js 的模板语法允许你声明式地将数据绑定到 DOM。以下是一些常见的模板语法和用法: 插值 插值语法用于在 HTML 中插入数据。 <p>{{ message }}</p>data:...

【C语言】fseek、ftell以及rewind函数(随机文件读写)

文章目录 前言1. fseek1.1 fseek函数原型1.2 fseek函数的形式参数1.3 fseek实例演示 2. ftell2.1 ftell函数原型2.2 ftell函数的实例演示 3. rewind3.1 rewind函数原型3.2 rewind函数实例演示 前言 在之前&#xff0c;我讲过文件的顺序读写。但是我们可不可以随机读写文件呢&a…...

使用 Elastic Observability 中的 OpenTelemetry 进行基础设施监控

作者&#xff1a;来自 Elastic ISHLEEN KAUR 将 OpenTelemetry 与 Elastic Observability 相结合&#xff0c;形成应用程序和基础设施监控解决方案。 在 Elastic&#xff0c;我们最近决定全面采用 OpenTelemetry 作为首要的数据收集框架。作为一名可观察性工程师&#xff0c;我…...

征服数据结构中的时间和空间复杂度

目录 时间复杂度推导大O方法求解时间复杂度的方法普通顺序结构单循环双循环递归Master定理&#xff08;主定理&#xff09;递归树方法 空间复杂度 一个算法的好坏根据什么来判断呢&#xff1f;有两种一种是时间效率&#xff0c;一种是空间效率。时间效率也可称为时间复杂度&…...

springboot Security vue

在使用Spring Boot Security与Vue.js构建前后端分离的应用时&#xff0c;你需要处理几个关键的技术点&#xff0c;包括认证&#xff08;Authentication&#xff09;和授权&#xff08;Authorization&#xff09;&#xff0c;以及如何处理跨域请求&#xff08;CORS&#xff09;、…...

13. 计算机网络HTTPS协议(一)

1. 前言 在上一章节中我们介绍了 HTTP 协议相关的面试题目,作为 HTTP 协议的扩展,HTTPS 协议也经常被面试官提起。 因为对于大部分的前端、后端开发者,都接触不到 HTTPS 协议的开发场景,因为我们往往只关注请求路径后缀,例如关注 URL: /get/username,而非路径全称 htt…...

Bean的作用域和生命周期

Bean的作用域 我们先来看下面这段代码 首先是一个Dog类 &#xff08;此处使用lombok来完成setter、getter、toString方法&#xff09; Setter Getter public class Dog {private String name;} 然后在DogBeanConfig类里面写一个返回Dog的方法&#xff0c;并将这个方法的返…...

【Qt】QMainWindow之菜单栏

目录 一.菜单栏 1.概念 2.组成 二.代码创建菜单栏 1.创建菜单栏 2.在菜单栏中添加菜单 3.在菜单中添加菜单项 三.图形化创建菜单栏 1.在打开Qt自带的ui文件界面后&#xff0c;得到以下界面 2.双击点击界面中&#xff08;在这里输入&#xff09;&#xff0c;在菜单栏中进行…...

uni-app封装组件实现下方滑动弹出模态框

子组件 <template><div class"bottom-modal" :class"{show: showModal}"><div class"modal-content" :class"{show: showModal}"><!-- 内容区域 --><slot></slot></div></div></…...

MATLAB(15)分类模型

一、前言 在MATLAB中&#xff0c;实现不同类型的聚类&#xff08;如K-means聚类、层次聚类、模糊聚类&#xff09;和分类&#xff08;如神经网络分类&#xff09;需要用到不同的函数和工具箱。下面我将为每种方法提供一个基本的示例代码。 二、实现 1. K-means聚类 % 假设X是…...

非虚拟机安装Centos7连接wifi并开机自动联网

一&#xff1a;确认网卡名称 ip addr 无线网卡是以 w 开头&#xff0c;确定是wlp4s0 &#xff0c;有的是 wlp5s0 二&#xff1a;配置网络 wpa_supplicant -B -i wlp4s0 -c <(wpa_passphrase "网络的名字" “网络的密码“) 设置自动分配IP dhclient wlp4s0 三&…...

怎么选择的开放式耳机好用?2024超值耳机分享!

耳机在当前数字化时代已成为我们生活、娱乐乃至工作中的重要部分。随着市场需求的增长&#xff0c;消费者对耳机的期望也在提高&#xff0c;他们不仅追求音质的卓越&#xff0c;还关注佩戴的舒适度和外观设计。虽然传统的入耳式和半入耳式耳机在音质上往往能够满足人们&#xf…...

Web 框架

Web 框架 Web服务器Web服务器的主要功能常见的Web服务器软件包 Web 框架常用 Python Web 框架选择Python Web框架的考虑因素 WSGIWSGI的主要特点WSGI的工作原理常见的WSGI服务器和框架&#xff1a; 静态资源定义与特点静态资源的类型静态资源的管理与优化 动态资源定义与特点动…...

嗖嗖移动业务大厅(JDBC)

一、项目介绍 1、项目背景: 该项目旨在模拟真实的移动业务大厅&#xff0c;。用户可以注册新卡、查询账单、管理套餐、充值话费、打印消费记录等功能。同时&#xff0c;项目还模拟了用户使用场景&#xff0c;如通话、上网、发短信等&#xff0c;并根据套餐规则进行相应的扣费…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型&#xff08;Primitive&#xff09; 和 对象类型&#xff08;Object&#xff09; 两大类&#xff0c;共 8 种&#xff08;ES11&#xff09;&#xff1a; 一、原始类型&#xff08;7种&#xff09; 1. undefined 定…...

【Linux】Linux 系统默认的目录及作用说明

博主介绍&#xff1a;✌全网粉丝23W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

代码规范和架构【立芯理论一】(2025.06.08)

1、代码规范的目标 代码简洁精炼、美观&#xff0c;可持续性好高效率高复用&#xff0c;可移植性好高内聚&#xff0c;低耦合没有冗余规范性&#xff0c;代码有规可循&#xff0c;可以看出自己当时的思考过程特殊排版&#xff0c;特殊语法&#xff0c;特殊指令&#xff0c;必须…...

MySQL:分区的基本使用

目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区&#xff08;Partitioning&#xff09;是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分&#xff08;分区&#xff09;可以独立存储、管理和优化&#xff0c;…...

消息队列系统设计与实践全解析

文章目录 &#x1f680; 消息队列系统设计与实践全解析&#x1f50d; 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡&#x1f4a1; 权衡决策框架 1.3 运维复杂度评估&#x1f527; 运维成本降低策略 &#x1f3d7;️ 二、典型架构设计2.1 分布式事务最终一致…...

使用SSE解决获取状态不一致问题

使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件&#xff0c;这个上传文件是整体功能的一部分&#xff0c;文件在上传的过程中…...

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...