【基础算法总结】多源 BFS_多源最短路问题

news2024/9/29 9:32:22

多源 BFS_多源最短路问题

  • 1.多源 BFS_多源最短路问题
  • 2.01 矩阵
  • 3.飞地的数量
  • 4.地图中的最高点
  • 5.地图分析

在这里插入图片描述

点赞👍👍收藏🌟🌟关注💖💖
你的支持是对我最大的鼓励,我们一起努力吧!😃😃

1.多源 BFS_多源最短路问题

最短路径问题有单源最短路径、多源最短路径、边权为 1 的最短路径、带负环的最短路等等。目前我们学了,边权为 1 的最短路径。

单源最短路径

前面一个专题用BFS 解决 边权为 1 的最短路径问题,都是单源最短路径问题。

一个起点一个终点 求最短路径
在这里插入图片描述

多源最短路径

多个起点一个终点 求从多个起点出发到终点的最短路径问题。
在这里插入图片描述

多源 BFS

用 BFS 解决边权为 1 的多源最短路径问题。

不管是单源还是多源只要用 BFS 解决边权都是为1的。边权是其他的是不能用BFS解决。也就是只要是用BFS解决最短路径问题,必须都是边权为1 !

如何解决?

解法一:暴力,把多源最短路径问题转化成若干个单源最短路径问题

也就是说给我若干个起点,用BFS暴力枚举出所有起点到终点的最短路径,然后取其中最短的路径。大概率是会超时的。

解法二:把所有的源点当成一个 超级源点,问题就变成了单一的单源最短路径问题

意思就是给我很多起点,我想办法把这些起点当成一个起点,问题就变长了从这一个超级起点开始到终点的最短路径了。仅需从这个超级起点出发来一次BFS就可以了。

在这里插入图片描述

这里可能会有疑惑,把所有起点当成一个超级起点出发最终得到的路径是正确答案吗?

这里我们感性的理解一下,所有起点的小人同时向外走一步。它们同时向外走一步,我们是可以舍去很多点的。比如有的起点小人向外走一步但是这一步已经被其他小人走过了,所以说从这个点向外走一步肯定没有其他点向外走一步更好,因此就可以舍去这个点。然后就相当于从超级起点出发向外走一步。把不好的都舍去只把好的保留,这就是超级源点干的事情。因为只保留好的,所以到达某一点绝对是最短的。

在这里插入图片描述

如何写代码呢?

这里的重点就是如何把所有起点搞成一个超级起点呢?特别简单,我们回忆一下 边权为1 单源最短路径问题 用 BFS 怎么解决,分为两步:

  1. 把起点加入到队列
  2. 一层一层往外扩

如何把所有起点搞成一个超级起点呢?

  1. 把所有起点加入到队列
  2. 一层一层往外扩

2.01 矩阵

题目链接: 542. 01 矩阵

题目分析:
在这里插入图片描述

给一个m*n的矩阵mat,返回一个同等大小的矩阵并且矩阵中每个格子都是到达0的最短距离。

在这里插入图片描述

算法原理:

解法一:一个位置一个位置求

遍历一下矩阵,一个一个位置BFS求到0的最短距离,但是会超时。

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

我们可以把所有的1当成一个超级起点,然后从这个起点做一次BFS,但是如果把1作为起点有一个致命问题,你更新不出来结果,把1当成超级起点从1找到0之后那是那个1到达的0?并且又如何回到开始位置去更新1到0的最短距离呢?

正着来起点到终点最短距离,那反着来终点到起点最短距离也是没问题的。所以,把所有的 0 当成起点,1 当成终点,当扩展到1的时候直接把距离更新到对应1的位置就行了。

  1. 把所有的 0 位置加入到队列中
  2. 一层一层的向外扩即可

刚开始遍历一下把所有0加入到队列中同时也把dist中对应位置更新成0,然后一层一层往外扩,我们是把队列中元素拿出来上下左右四个方向像外扩。当层序遍历结束之后这个dist也就填完了。把dist返回就可以了。

在这里插入图片描述

这里有一些细节问题:

回忆求边权为 1 的单源最短路径,我们写代码时是需要一个bool类型vis二维数组标记当前位置是否被搜索过,并且层序遍历中还需要step记录当前扩展到那一层,sz记录当前队列中的元素是把队列中所有元素都往外扩一层,结合step知道当前扩展到这一层的步数是多少。

这道题我们仅需一个dist二维数组就行了,不需要上面三个东西。先看这个bool数组,其实我们可以把dist数组里面的值全部都初始化-1来标记当前位置没有被搜索过。step和sz也不用要,我们直接从dist数组中就可以更新下一个位置中dist的值,之前是从[a,b] 上下左右扩展 [x,y],这次从[a,b] 扩展到 [x,y] dist中已经记录[a,b]位置的值了,仅需dist[x][y] = dist[a][b] + 1 即可。而且也不用搞一个sz一层一层往外扩,我们可以一个元素一个元素往下扩,原因就是dist已经标记当前元素是处于那一层的。

在这里插入图片描述

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 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;

        // 1. 把所有的源点加⼊到队列中
        for(int i = 0; i < m; ++i)
            for(int j = 0; j < n; ++j)
                if(mat[i][j] == 0)
                {
                    q.push({i,j});
                    dist[i][j] = 0;
                }

        // 2. ⼀层⼀层的往外扩 (因为dist每个起点的开始层数了,因此不用再搞一个sz)
        while(q.size())
        {
            auto [a,b] = q.front();
            q.pop();
            for(int k = 0; k < 4; ++k)
            {
                int x = a + dx[k], y = b + dy[k];
                if(x >= 0 && x < m && y >= 0 && y < n && dict[x][y] == -1)
                {
                    dict[x][y] = dict[a][b] + 1;
                    q.push({x,y});
                }
            }            
        }
        return dist;
    }
};

3.飞地的数量

题目链接: 1020. 飞地的数量

题目分析:

在这里插入图片描述

返回矩阵中无法通过边界离开网格的陆地的数量。

算法原理:

解法一:一个一个去判断
遍历矩阵当遇到一个1的时候就去判断能不能走出去。时间复杂度很恐怖。

但是可以一个一个去判断做一些优化,当遇到一个1的时候先做一次BFS看与这个1相连的连通块能不能到边界,如果能的话,然后再来一次BFS统计1的个数并且标记一下该位置已经被搜索过,如果不能的话把这块地方标记为0。需要写两份不同的BFS代码。

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

我不判断1这个位置能不能走到边界,而是判断边界上的1能不能走到你。把所有边界1当作一个超级起点向内搜索,把搜索到的1都标记一下表明这些位置都是能走出去的。最后再搜索一下看看那些1是没被标记过的统计一下就是答案。

在这里插入图片描述

class Solution {
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
public:
    int numEnclaves(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();
        vector<vector<bool>> vis(m , vector<bool>(n));
        queue<pair<int,int>> q;

        // 1.把边上的 1 加入到队列中
        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({i,j});
                        vis[i][j] = true;
                    }

        // 2.多源 bfs     
        while(q.size())
        {
            auto [a,b] = q.front();
            q.pop();
            for(int k = 0; k < 4; ++k)
            {
                int x = a + dx[k], y = b + dy[k];
                if(x >= 0 && x < m && y >= 0 && y < n && grid[x][y] && !vis[x][y])
                {
                    q.push({x,y});
                    vis[x][y] = true;
                }
            }
        }

        // 3.统计结果
        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;

    }
};

4.地图中的最高点

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

题目分析:

在这里插入图片描述

给一个m*n的矩阵,格子里面0代表陆地,1代表水域。

按照下面要去给每个格子安排高度:

每个格子的高度都必须是非负的。

如果一个格子是 水域 ,那么它的高度必须为 0

任意相邻的格子高度差 至多 为 1 。当两个格子在正东、南、西、北方向上相互紧挨着,就称它们为相邻的格子。(也就是说它们有一条公共边)

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

算法原理:

按照上面的要求,我们可以先安排水域,如果你安排其他地方,它要受它上下左右的控制才行不能随意给一个数。将所有水域变成0然后按照多源BFS走一次就行了。因为要求高度值最大,因此每个临近位置都+1往外扩。这里和前面一道题几乎一模一样。

在这里插入图片描述

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 m = isWater.size(), n = isWater[0].size();
        vector<vector<int>> dist(m , vector<int>(n, -1));
        queue<pair<int,int>> q;

        // 1. 把所有的源点加⼊到队列⾥⾯
        for(int i = 0; i < m; ++i)
            for(int j = 0; j < n; ++j)
                if(isWater[i][j] == 1)
                {
                    q.push({i,j});
                    dist[i][j] = 0;
                }
        // 2. 多源 bfs
        while(q.size())
        {
            auto [a,b] = q.front();
            q.pop();

            for(int k = 0; k < 4; ++k)
            {
                int x = a + dx[k], y = b + dy[k];
                if(x >= 0 && x < m && y >= 0 && y < n && dist[x][y] == -1)
                {
                    dist[x][y] = dist[a][b] + 1;
                    q.push({x,y});
                }
            }
        }
        return dist;
    }
};

5.地图分析

题目链接: 1162. 地图分析

题目分析:

在这里插入图片描述

给一个 n x n 的 网格 grid,上面的每个 单元格 都用 0 和 1 标记好了。其中 0 代表海洋,1 代表陆地。

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

「曼哈顿距离」( Manhattan Distance):(x0, y0) 和 (x1, y1) 这两个单元格之间的距离是 |x0 - x1| + |y0 - y1| 。其实就是最短路径

在这里插入图片描述

算法原理:

解法: 多源BFS + 正难则反

从海洋找陆地不好搞路径,反过来从陆地到海洋。陆地初始为0。

在这里插入图片描述

class Solution {
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
public:
    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)
                {
                    q.push({i,j});
                    dist[i][j] = 0;
                }
        

        int ret = -1;
        while(q.size())
        {
            auto [a,b] = q.front();
            q.pop();
            for(int k = 0; k < 4; ++k)
            {
                int x = a + dx[k], y = b + dy[k];
                if(x >= 0 && x < m && y >= 0 && y < n && dist[x][y] == -1)
                {
                    dist[x][y] = dist[a][b] + 1;
                    q.push({x,y});
                    ret = max(ret, dist[x][y]);
                }
            }
        }
        return ret;

    }
};

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

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

相关文章

springboot纹理生成图片系统--论文源码调试讲解

第2章 程序开发技术 2.1 MySQL数据库 开发的程序面向用户的只是程序的功能界面&#xff0c;让用户操作程序界面的各个功能&#xff0c;那么很多人就会问&#xff0c;用户使用程序功能生成的数据信息放在哪里的&#xff1f;这个就需要涉及到数据库的知识了&#xff0c;一般来说…

Maven继承和聚合特性

目录 Maven继承关系 1.继承概念 父POM 子模块 2.继承机制 3.示例 4.继承作用 背景 需求 5.注意事项 Maven聚合关系 1. 定义与概念 2. 实现方式 3. 特性与优势 4. 示例 5. 注意事项 Maven继承关系 1.继承概念 Maven 继承是指在 Maven 的项目中&#xff0c;定义…

沉浸式技术

沉浸式技术是一种通过创造逼真的虚拟或增强现实环境&#xff0c;使用户感到自己仿佛身处另一个世界的技术。它主要依赖于视觉、听觉、触觉等多种感官的调动&#xff0c;带来身临其境的体验。随着技术的发展&#xff0c;沉浸式技术正迅速改变着娱乐、教育、医疗等众多领域。本文…

Golang | Leetcode Golang题解之第345题反转字符串中的元音字母

题目&#xff1a; 题解&#xff1a; func reverseVowels(s string) string {t : []byte(s)n : len(t)i, j : 0, n-1for i < j {for i < n && !strings.Contains("aeiouAEIOU", string(t[i])) {i}for j > 0 && !strings.Contains("aei…

牛客周赛 Round 56

牛客周赛 Round 56 A 面包店故事 链接&#xff1a;https://ac.nowcoder.com/acm/contest/88392/A 来源&#xff1a;牛客网 题目描述 小镇上有一家面包店&#xff0c;面包以 &#x1d465; 元的价格出售&#xff0c;加 &#x1d466; 元可以多加几块培根。小歪带着 &#x1d4…

蔚来汽车拥抱AI

30多个传感器&#xff0c;车上实时收集数 为什么要造手机 领航辅助驾驶 端到端AEB

Spring动态代理与AOP

AOP中的Before是如何实现的&#xff1f; 在AOP&#xff08;面向切面编程&#xff09;中&#xff0c;Before注解通常用于定义一个在方法执行前执行的前置通知&#xff08;advice&#xff09;。在Spring框架中&#xff0c;实现Before功能的底层机制主要基于代理&#xff08;Prox…

JSON Web Token (JWT): 理解与应用

JWT&#xff08;JSON Web Token&#xff09;是一种开放标准&#xff08;RFC 7519&#xff09;&#xff0c;它定义了一种紧凑且自包含的方式&#xff0c;用于在各方之间以JSON对象的形式安全地传输信息。JWT通常用于身份验证和授权目的&#xff0c;因为它可以使用JSON对象在各方…

4.5、配置vtp域

一、了解vtp域 VTP&#xff08;VLAN Trunking Protocol&#xff09;域是一个在网络中用于管理和同步VLAN配置信息的概念。它使得多个交换机可以在同一VTP域中共享VLAN信息&#xff0c;从而简化了VLAN的配置和管理。 三种主要模式 Server模式&#xff1a; 交换机可以创建、修…

Nginx的进程模型:Master-Worker架构解析

Nginx的进程模型&#xff1a;Master-Worker架构解析 一、Master-Worker架构概述二、Master进程的职责三、Worker进程的特点四、与Apache进程模型的对比 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; Nginx作为高性能Web服务器&#xff0c…

代码随想录算法训练营day45:动态规划part12:115.不同的子序列;583. 两个字符串的删除操作;72. 编辑距离

目录 115.不同的子序列 分析&#xff1a; 583. 两个字符串的删除操作 72. 编辑距离 115.不同的子序列 力扣题目链接(opens new window) 给定一个字符串 s 和一个字符串 t &#xff0c;计算在 s 的子序列中 t 出现的个数。 字符串的一个 子序列 是指&#xff0c;通过删除…

初识Linux · 基本指令(1)

目录 前言&#xff1a; 基本指令 1.1 pwd 1.2 ls 1.3 mkdir cd clear 1.4 touch 1.5 ls部分补充 1.6 whoami 1.7 有关目录以及路径 前言&#xff1a; 今天是Linux系列的第一章节&#xff0c;对于Linux的主线学习大概会更新两个半月左右&#xff0c;中间穿插着算法…

vue中 在scoped下通过@import引入scss的作用域?

<style lang"scss" src"./index.scss" scoped></style>人工智能学习网站 https://chat.xutongbao.top

nbcio-boot基于flowable6.7.2的流程模型版本管理-前端与界面

更多技术支持与服务请加入我的知识星球。 这部分主要讲前端与功能界面方面 1、首先增加发布列表与修改状态api接口 // 查询流程发布列表 export function listPublish(query) {return request({url: /flowable/definition/publishList,method: get,params: query})}// 激活/挂…

pytorch之nn.Module使用介绍

在 PyTorch 中&#xff0c;nn.Module 是所有神经网络模型的基类&#xff0c;提供了许多重要的成员函数。以下是一些常用的成员函数及其功能&#xff1a; 1. __init__(self) 描述&#xff1a;初始化模块。在用户定义的模型中&#xff0c;通常用来定义层和其他模块。 示例&…

【hot100篇-python刷题记录】【最大子数组和】

R5-普通数组 印象题&#xff0c;讲思路&#xff1a; 1.0个元素&#xff0c;返回0 2.将从left到right的计算简化为为left-mid&#xff0c;mid1-right 以及left-mid-right 3者的最大值&#xff08;因为有负数&#xff09; 3.上面左右两边的计算可以递归调用本身函数&#xff0…

第二十二节、创建人物状态栏

一、可视化插件 在层级面板名字加上对应的图标&#xff0c;会显示颜色&#xff0c;需要运行一下 二、UI 1、创建一个画布 由于使用新的新输入系统&#xff0c;需要替换一下 2、设置锚点 作用是&#xff1a;当屏幕分辨率更改后&#xff0c;ui图标不会位移 3、设置填充 4、制…

tomcat 运行javaweb项 提示无法将资源添加到Web应用程序缓存解决方法

javaweb项目tomcat启动提示web资源缓存不足&#xff0c;具体如下&#xff0c;不影响项目运行 15-Aug-2024 13:35:20.200 警告 [localhost-startStop-1] org.apache.catalina.webresources.Cache.getResource 无法将位于[/WEB-INF/classes/web-vue2/ssdev/ux/login/style/font/f…

2000-2022年 上市公司代理成本(原始数据、上市公司代理成本的最终结果、do文件,参考文献等等)

上市公司代理成本&#xff08;2000-2022年&#xff09; 上市公司的代理成本是公司治理中一个重要的概念&#xff0c;它涉及到公司内部不同利益相关者之间的利益冲突和协调问题。主要包含以下几个方面&#xff1a; 监督成本&#xff1a;股东为了确保经理人的行为符合公司和股东的…

VR游戏移植到Apple Vision Pro的技术挑战与解决方案

核心观点: 30Hz手部追踪在90Hz游戏中的适配 是最大挑战,需要创新性解决方案。Vision Pro的独特架构 要求重新思考着色器编译和缓存策略。全沉浸模式下的空间音频实现 需要自定义解决方案。早期适配 可能面临技术限制,但也带来市场先机。学习指南: 深入研究Vision Pro的手部…