dijkstra算法相关(使用邻接表和优先队列两种方法)力扣题:743. 网络延迟时间(有向图);1334. 阈值距离内邻居最少的城市(无向图)

news2025/4/9 11:18:06

具体dijkstra算法就不展开说了,因为太多帖子来解释了,并且这也只是我的个人总结/记录,我会把自己的思考过程写在代码的注释中。

743. 网络延迟时间(有向图)

有 n 个网络节点,标记为 1 到 n。

给你一个列表 times,表示信号经过 有向 边的传递时间。 times[i] = (ui, vi, wi),其中 ui 是源节点,vi 是目标节点, wi 是一个信号从源节点传递到目标节点的时间。

现在,从某个节点 K 发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 -1 。

在这里插入图片描述

1. 邻接表法

	class Solution {
public:
    // distances数组 保存:起点k 到其他点的最短距离
    // visited数组 保存:某点是否被访问过了,被访问过则设置为true
    // graph 二维数组:邻接表
    // n : 节点总数
    void dijkstra(vector<vector<long long>>& graph,vector<int>& distances,int n,int k,vector<bool>& visited){
        distances[k] = 0;// 起始点到起始点自身的距离为0

        // 这里只需要循环 n-1次
        // 原因:除k点以外只有 n-1个点,每循环一次,就更新k点到一个点的距离
        for(int i = 1;i<=n-1;i++){
            int id = 0,minDistance = INT_MAX;
            for(int j = 1;j<=n;j++){
                // 这个循环的目的:去找 距离 k点最近的点
                // 原因:可以通过 这个点,去更新 其他点到 k点的距离
                if(!visited[j] && distances[j]<minDistance){
                    minDistance = distances[j];
                    id = j;
                }
            }
            // 所有点都被访问过了 或者 所有点都不可达
            if(id == 0) return;
            visited[id] = true;

            // 得到一个中间点 id后,比较k->id->某一点的距离 和 k->某一点的距离 
            // 来更新distances数组,注意,这个数组存的是k到某一点的距离
            for(int j = 1;j<=n;j++){
                if(!visited[j] && distances[id]+graph[id][j]<distances[j]){
                    distances[j] = distances[id]+graph[id][j];
                }
            }
        }
    }

    int networkDelayTime(vector<vector<int>>& times, int n, int k) {
        vector<vector<long long>> graph(n+1,vector<long long>(n+1,INT_MAX));
        vector<int> distances(n+1,INT_MAX);
        vector<bool> visited(n+1,false);

        // 建立邻接表
        for(auto t:times){
            int u = t[0],v = t[1],w = t[2];
            graph[u][v] = w;
        }

        //dijkstra算法
        dijkstra(graph,distances,n,k,visited);

        int ans = 0;
        for(int i = 1;i<=n;i++){
            if(distances[i] == INT_MAX) return -1;
            ans = max(ans,distances[i]);
        }
        return ans;
    }
};

2. 优先队列

class Solution {
public:
    void dijktra(vector<vector<int>>& times,vector<int>& dis, int n, int k){
        dis[k] = 0;
        using Pair = pair<int,int>; // first是距离,second是目标点
        priority_queue<Pair,vector<Pair>, greater<Pair>> pq;

        pq.push({0,k});

        while(!pq.empty()){
            auto e = pq.top();
            pq.pop();
            if(e.first>dis[e.second]) continue;
            for(int i = 0;i<times.size();i++){
                if(times[i][0] == e.second){
                    int v = times[i][1];
                    // 到v点的的距离
                    int w = e.first+times[i][2];
                    if(dis[v]==-1 || dis[v]>w){
                        dis[v] = w;
                        pq.emplace(w,v);
                    }
                }
            }
        }
    }

    int networkDelayTime(vector<vector<int>>& times, int n, int k) {
        vector<int> dis(n+1,-1);

        dijktra(times,dis,n,k);

        int ans = 0;
        for(int i = 1;i<=n;i++){
            if(dis[i]==-1) return -1;
            ans = max(ans,dis[i]);
        }
        return ans;
    }
};

1334. 阈值距离内邻居最少的城市

有 n 个城市,按从 0 到 n-1 编号。给你一个边数组 edges,其中 edges[i] = [fromi, toi, weighti] 代表 fromi 和 toi 两个城市之间的双向加权边,距离阈值是一个整数 distanceThreshold。

返回能通过某些路径到达其他城市数目最少、且路径距离 最大 为 distanceThreshold 的城市。如果有多个这样的城市,则返回编号最大的城市。

注意,连接城市 i 和 j 的路径的距离等于沿该路径的所有边的权重之和。

在这里插入图片描述

1. 邻接表法

class Solution {
public:
    void Dijkstra(vector<vector<long long>>& graph,vector<int>& distances,vector<bool> &visited,int n,int distanceThreshold,int start){
        // 自身到自身的距离为0
        distances[start] = 0;

        for(int i = 0;i<n-1;i++){
            int u = -1,minDis = INT_MAX;
            // 下面这个这个循环的目的:
            // 为了在 和 start 点相连的所有点中找到一个最近的点,再把它设为新的起点
            for(int j = 0;j<n;j++){
                if(!visited[j] && distances[j] <minDis){
                    u = j; // 设置新的起点
                    minDis =distances[j];
                }
            }
            // 如果所有点都访问过了 或者 不可达,直接return 即可
            if(u==-1) return;
            // 把新的起点设置为访问过
            visited[u] = true;

            // 接下来更新 start到所有点的 新的 距离
            // 为什么有新的距离?
            // 回答:因为此时我们有了一个新的点,那么从 start点开始到其他点就不止一种直连路线
            // 而是可以借助 刚刚确立好的新的点 ,比如从 start到某点 需要距离为5
            // 而start 到 u 的距离为1,u到某点的距离为2,那么就可以更新新的距离了
            for(int j = 0;j<n;j++){
                // 注意:仍然需要不去管那些已经访问过的节点
                //因为已经访问过的节点就已经是最短的距离了
                if(!visited[j] && distances[u]+graph[u][j]<distances[j]){
                    distances[j] = distances[u]+graph[u][j];
                }
            }
        }
    }

    //  使用Dijkstra算法,邻接矩阵版
    int findTheCity(int n, vector<vector<int>>& edges, int distanceThreshold) {
        vector<vector<long long>> graph(n,vector<long long>(n,INT_MAX));// 邻接矩阵
        for(auto edge:edges){
            int u = edge[0],v = edge[1],w = edge[2];
            graph[u][v] = graph[v][u] = w;
        }

        // minCount:在指定的阈值内可以 到达节点 的最少数量
        int idx = -1,minCount = INT_MAX;
        for(int i = 0;i<n;i++){
            vector<int> distances(n,INT_MAX);// 单源最短路径数组
            vector<bool> visited(n,false); // 用来记录某一节点是否被访问过
            // 调用函数可以得到从i点出发到其他各个点的最短距离
            // 这些距离被保存在distances数组中
            Dijkstra(graph,distances,visited,n,distanceThreshold,i);
            int count = 0; // 小于等于阈值的城市个数
            for(int j = 0;j<n;j++){
                if(i!=j && distances[j] <= distanceThreshold  ){
                    count++;
                }
            }
            if(count<=minCount){
                minCount = count;
                // 保存当下这个出发点
                idx = i;
            }
        }
        return idx;
    }
};

2. 优先队列

class Solution { //优先队列版
public:
    void Dijkstra(vector<vector<int>>& graph, vector<int>& distances, int n, int distanceThreshold, int start) {
        //小顶堆,按照距离dist从小到大排序,pair中first存dist
        priority_queue <pair<int, int>,vector<pair<int, int>>, greater<pair<int, int>>> q;
        distances[start] = 0;
        q.push({distances[start],start});
        while (!q.empty()) {
            pair<int, int>p = q.top();
            int u = p.second;
            q.pop();
            if (distances[u] < p.first) {
                continue;
            }
            for (int v=0; v<n; ++v) {
                if (graph[u][v] != INT_MAX && distances[v]>distances[u]+graph[u][v]) {
                    distances[v]=distances[u]+graph[u][v];
                        q.push({distances[v],v});
                }
            }
        }
    }
    int findTheCity(int n, vector<vector<int>>& edges, int distanceThreshold) {
        vector<vector<int>>graph(n,vector<int>(n,INT_MAX)); //邻接矩阵
        for (vector<int> edge : edges) {
            int u=edge[0], v=edge[1], w=edge[2];
            graph[u][v] = graph[v][u] = w;
        }
        int idx = -1, minCount = INT_MAX;
        for (int i=0; i<n; ++i) {
            vector<int>distances(n,INT_MAX); //单源最短路径数组
            Dijkstra(graph, distances, n, distanceThreshold, i);
            int count = 0; //小于等于距离阈值的城市个数
            for (int j=0; j<n; ++j) {
                if (distances[j]<=distanceThreshold && i!=j) {
                    count++;
                }
            }
            if (count <= minCount) {
                minCount = count;
                idx = i;
            }
        }
        return idx;
    }
};

最后:

其实dijkstra算法(邻接表版本)对有向图和无向图使用起来都是一样的,没有区别。我之前会想如果我把[0,3,2]中的0和3调换会不会情况不一样,答案是不会的。因为在建邻接表的时候,就把双向的距离给设置好了,如果调换顺序,不过是从另一个点出发,距离仍然一样,并且也不用担心重复访问的问题,因为使用了visited数组来区分。

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

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

相关文章

ArduPilot开源飞控之MAVProxy简介

ArduPilot开源飞控之MAVProxy简介 1. 源由2. 特点3. 安装 & 更新3.1 安装Step 1: 烧录raspberryPi镜像Step 2&#xff1a;apt软件包更新Step 3&#xff1a;Raspian系统更新Step 4&#xff1a;安装依赖环境Step 5&#xff1a;安装mavproxyStep 6&#xff1a;配置bash环境 3.…

HttpRunner自动化测试之脚手架工具使用(一键搭建)

脚手架工具使用&#xff1a; 每一个成熟的系统工具&#xff0c;都会有对应的脚手架工具&#xff0c;它可以快速构建项目的必要目录&#xff0c;不必自己一个一个的配置与搭建&#xff0c;只需要执行一些命令即可。 httprunner也提供了脚手架工具&#xff0c;使用步骤如下&…

Python接口自动化-requests模块之post请求

一、源码解析 def post(url, dataNone, jsonNone, **kwargs):r"""Sends a POST request.:param url: URL for the new :class:Request object.:param data: (optional) Dictionary, list of tuples, bytes, or file-likeobject to send in the body of the :cla…

微服务——ES实现自动补全

效果展示 在搜索框根据拼音首字母进行提示 拼音分词器 和IK中文分词器一样的用法&#xff0c;按照下面的顺序执行。 # 进入容器内部 docker exec -it elasticsearch /bin/bash# 在线下载并安装 ./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch…

迭代器模式-遍历聚合对象中的元素

在开发中&#xff0c;我们经常使用到Iterator这个接口&#xff0c;我们很疑惑于这个接口的作用&#xff0c;认为集合已经实现了数据访问的方法&#xff0c;增加Iterator的意义在哪。本文我们将学习迭代器模式&#xff0c;用以探讨Iterator的作用。 1.1 迭代器模式概述 提供一…

地图 SDK gitlab 测试代码环境配置

文章目录 1、Gradle 插件版本和 Gradle 版本2、NDK 路径3、JDK 版本4、修改变量5、重新 BuildQ&A&#xff1a; test 用例启动之后问题问题描述 拉下项目的 dev 分支&#xff0c;然后依赖的 mapsdk-base 也完成下载 &#xff0c;之后就是Android Studio 配置环境 1、Gradle …

【Git】保姆级详解:Git配置SSH Key(密钥和公钥)到github

博主简介&#xff1a;22级计算机科学与技术本科生一枚&#x1f338;博主主页&#xff1a;是瑶瑶子啦每日一言&#x1f33c;: “当人们做不到一些事情的时候&#xff0c;他们会对你说你也同样不能。”——《当幸福来敲门》 克里斯加德纳 Git配置SSH Key 一、什么是Git?二、什么…

如何给Google Chrome增加proxy

1. 先打开https://github.com/KaranGauswami/socks-to-http-proxy/releases 我的电脑是Liunx系统所以下载第一个 2. 下载完之后把这个文件变成可执行文件&#xff0c;可以是用这个命令 chmod x 文件名 3. 然后执行这个命令&#xff1a; ./sthp-linux -p 8080 -s 127.0.0.1:…

Jwt(Json web token)——使用token的权限验证方法 用户+角色+权限表设计 SpringBoot项目应用

目录 引出使用token的权限验证方法流程 用户、角色、权限表设计权限表角色表角色-权限关联表用户表查询用户的权限&#xff08;四表联查&#xff09;数据库的视图 项目中的应用自定义注解拦截器controller层DTO返回给前端枚举类型的json化日期json问题 实体类-DAO 总结 引出 1.…

学习pytorch

学习pytorch 1. 环境安装配置镜像源conda命令记录遇到的问题1. torch.cuda.is_available() False 1. 环境安装 B站小土堆视频 配置镜像源 conda config --show channels conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/mainhttp://www.m…

leetcode 图算法小结

文章目录 1 DFS和BFS797. 所有可能的路径200. 岛屿数量 1 DFS和BFS 深度优先遍历一般采用回溯算法进行解决。回溯算法&#xff0c;其实就是dfs的过程。 void dfs(参数) {处理节点dfs(图&#xff0c;选择的节点); // 递归回溯&#xff0c;撤销处理结果 }广度优先搜索理解为层次…

Java-数据类型

数据类型 数据类型基本数据类型整形浮点字符型布尔类字节 引用数据类型类型转换显式转换隐式转换注意事项 整型提升 作为学习Java的入门知识,在刚开始面试的几场,表现不太好的时候,就有几个面试官会问这个问题,估计此时此刻我在他们的心目中也就是这个问题的层次了吧…当然,当时…

Linux网络服务之自动装机(PXE+KICKSTART)详解

自动装机 一、启动操作系统的方式1.1 系统装机的三种引导方式1.2 系统安装过程1.3 三大文件1.4 如何实现自动装机&#xff1f; 二、PXE2.1 PXE的简介和优点2.2 实现PXE的前提条件2.3 PXE实现过程2.5 要安装的服务2.6 实现PXE2.6.1 前置准备2.6.2 安装并配置DHCP2.6.3 安装并配置…

Nginx负载均衡搭建

目录 1、准备一台装有nginx服务的主机 2、所需模块说明&#xff1a; 3、两台Web服务器主机 4、 修改nginx的配置文件 5、查看结果&#xff1a; 1、准备一台装有nginx服务的主机 LVS—DR集群的搭建_.98℃的博客-CSDN博客 2、所需模块说明&#xff1a; Nginx http 功能模…

【音视频】vms布署说明

目录 外场布署场景&#xff08;99%&#xff09; 研发实验场景&#xff08;1%&#xff09; 高级玩法 证书安装方法 外场布署场景&#xff08;99%&#xff09; 下面两种场景&#xff0c;为本产品主要应用场景&#xff0c;2023-08-08日后&#xff08;统一所有证书&#xff09;…

入门平台工程的福音,麦肯锡刚发布了平台工程蓝图

在软件开发和工程效能领域&#xff0c;平台工程 (Platform Engineering) 是继 DevOps 后逐渐兴起的主流概念。平台工程&#xff0c;顾名思义&#xff0c;就是通过组合一系列标准化的软件开发工具&#xff0c;构建起一个标准化的研发平台。目标则是为了提高开发者体验和生产力。…

构建Docker容器监控系统 (1)(Cadvisor +InfluxDB+Grafana)

目录 Cadvisor InfluxDBGrafana 1. Cadvisor 2.InfluxDB 3.Grafana 开始部署&#xff1a; 下载组件镜像 创建自定义网络 创建influxdb容器 创建数据库和数据库用户 创建Cadvisor 容器 准备测试镜像 创建granafa容器 访问granfana 添加数据源 Add data source 新建 …

python接口自动化之自动发送测试报告邮件

前言 ​ SMTP&#xff08;Simple Mail Transfer Protocol&#xff09;也就是简单邮件传输协议&#xff0c;是一种提供可靠且有效电子邮件传输的协议。python的smtplib模块就提供了一种很方便的途径发送电子邮件&#xff0c;它对smtp协议进行了简单的封装。 ​ python发邮件主…

四 、Mysql 开发

四 、Mysql开发 102 可以使用MySQL直接存储文件吗&#xff1f; 可以使用 BLOB (binary large object)&#xff0c;用来存储二进制大对象的字段类型。 TinyBlob 255 值的长度加上用于记录长度的1个字节(8位) Blob 65K值的长度加上用于记录长度的2个字节(16位) MediumBlob 16M值…

AutoJS自定义悬浮菜单(附完整代码)

我们在开发Autojs脚本时&#xff0c;需要使用到悬浮窗功能来控制脚本。那么到底要如何来做呢&#xff1f;今天给大家分享一些&#xff0c;先来看看效果&#xff1a; 调整移动和贴边。 防止滑出屏幕 附上完整代码 var storage storages.create("日赚3万_短视频合集&quo…