最短路Dijkstra求最短路(讲解 + 模板 + 例题)

Dijkstra算法

Dijkstra是基于贪心思想的单源最短路算法;

变量定义 : 

const int N = 510;
const int INF = 1e9 + 10 ;
struct edge{
	int  v , w ; // 表示出边和边权 
}; 
vector<edge> e[N] ;
int d[N] ; // dis[u]存u到源点s的最短距离 
int vis[N] ;// vis[u]标记u是否出圈 
int n , m  , s ;

核心思路也就是  : 对u操作的时候 , 有出边u->v(设边权为w),那么就可以尝试更新d[v] = min(d[v] , d[u]+w) ;

图解示例 : 

注 : 对负边权可能会出错;

模板(朴素版)  : 

时间复杂度 : O(n^2 + m) == O(n^2)

const int N =1e4 + 10;
const int INF = 1e9 + 10 ;
struct edge{
	int  v , w ; // 表示出边和边权 
}; 
vector<edge> e[N] ;
int d[N] ; // dis[u]存u到源点s的最短距离 
int vis[N] ;// vis[u]标记u是否出圈 
int n , m  , s ;

void dijkstra(int s){
    for(int i=0;i<=n;i++) d[i] = INF ;
    d[s] = 0 ;
	for(int i=1;i<n;i++){//枚举次数 
		int u = 0 ;// 相当于哨兵
		for(int j=1;j<=n;j++) 
			if(!vis[j]&&d[j]<d[u]) 
				u = j ;
 		vis[u] = 1 ;// 标记u以出圈
		for(auto ed : e[u]){// 枚举邻边 
			int v = ed.v , w = ed.w ;
			if(d[v]>d[u]+w)
				d[v] = d[u] + w ;
		}	
	}
}

堆优化版 

模拟步骤 : 

用优先队列优化找最小点的过程 : 

创建一个pair类型的大根堆q{-距离,点},把距离取负值,距离最小的元素最大,一定在堆顶 ;

  1. 初始时 , 所有点都在圈(集合)内 , vis= 0 , d[s] = 0 , d[其他点]=INF ;

  2. 从队头弹出距离最小的点u,若u扩展过则跳出,否则打标记

  3. 对u的所有出边执行松弛操作,把{-d[u],v}压入队尾 ;

  4. 重复2,3操作,直达队列为空 ;

模板 : 

const int N =1e4 + 10;
const int INF = INT_MAX ;
typedef pair<int,int> PII ;
struct edge{
	int  v , w ; // 表示出边和边权 
}; 
vector<edge> e[N] ;
int d[N] ; // dis[u]存u到源点s的最短距离 
int vis[N] ;// vis[u]标记u是否出圈
priority_queue<PII> q ; // 距离取负 q{-距离,点} , 距离最小的元素最大,一定在堆顶 
int n , m  , s ;

void dijkstra_queue(int s){
	for(int i=0;i<=n;i++) d[i] = INF ;
	d[s] = 0 ; 
	q.push({0,s}) ;
	while(q.size()){
		auto t = q.top() ; q.pop() ;
		int u = t.second ;
		if(vis[u]) continue ;// 出过队直接跳 
		vis[u] = 1 ;// 标记u已经出队
		for(auto ed : e[u]){
			int v = ed.v  , w = ed.w ;
			if(d[v] > d[u]+w){
				d[v] = d[u] + w ;
				q.push({-d[v],v}) ;// 大根堆 
			}
		} 
	}
}

时间复杂度 : 

复杂度 : O(mlogm)

路径的记录与输出 : 

用一个pre[]数组记录前驱结点即可:

对比 : 

例题 : 

洛谷3371

【模板】单源最短路径(弱化版) - 洛谷

AC代码 : 

#include<bits/stdc++.h>
using namespace std;
const int N =1e4 + 10;
const int INF = INT_MAX ;
typedef pair<int,int> PII ;
struct edge{
	int  v , w ; // 表示出边和边权 
}; 
vector<edge> e[N] ;
int d[N] ; // dis[u]存u到源点s的最短距离 
int vis[N] ;// vis[u]标记u是否出圈
int pre[N] ;
priority_queue<PII> q ; // 距离取负 q{-距离,点} , 距离最小的元素最大,一定在堆顶 
int n , m  , s ;

void dijkstra_queue(int s){
	for(int i=0;i<=n;i++) d[i] = INF ;
	d[s] = 0 ; 
	q.push({0,s}) ;
	while(q.size()){
		auto t = q.top() ; q.pop() ;
		int u = t.second ;
		if(vis[u]) continue ;// 出过队直接跳 
		vis[u] = 1 ;// 标记u已经出队
		for(auto ed : e[u]){
			int v = ed.v  , w = ed.w ;
			if(d[v] > d[u]+w){
				d[v] = d[u] + w ;
				pre[v] = u ;
				q.push({-d[v],v}) ;// 大根堆 
			}
		} 
	}
}

void dfs_path(int u){// 递归输出路径 
	if(u==s){printf("%d ",u);return ;}
	dfs_path(pre[u]) ;
	printf("%d ",u);
}

void dijkstra(int s){
    for(int i=0;i<=n;i++) d[i] = INF ;
    d[s] = 0 ;
	for(int i=1;i<n;i++){//枚举次数 
		int u = 0 ;// 相当于哨兵
		for(int j=1;j<=n;j++) 
			if(!vis[j]&&d[j]<d[u]) 
				u = j ;
 		vis[u] = 1 ;// 标记u以出圈
		for(auto ed : e[u]){// 枚举邻边 
			int v = ed.v , w = ed.w ;
			if(d[v]>d[u]+w)
				d[v] = d[u] + w ;
		}	
	}
}


int main(){
	cin >> n >> m >> s ;
	for(int i=0;i<m;i++){
		int a , b , c ; cin >> a >> b >> c ;
		e[a].push_back({b,c});
	}
	dijkstra_queue(s) ;
	for(int i=1;i<=n;i++) cout << d[i] << " " ;
	// dfs_path(4) ;
}

洛谷4779

【模板】单源最短路径(标准版) - 洛谷

AC代码 : 

#include<bits/stdc++.h>
using namespace std;
const int N =1e5 + 10;
const int INF = INT_MAX ;
typedef pair<int,int> PII ;
struct edge{
	int  v , w ; // 表示出边和边权 
}; 
vector<edge> e[N] ;
int d[N] ; // dis[u]存u到源点s的最短距离 
int vis[N] ;// vis[u]标记u是否出圈
int pre[N] ;
priority_queue<PII> q ; // 距离取负 q{-距离,点} , 距离最小的元素最大,一定在堆顶 
int n , m  , s ;

void dijkstra_queue(int s){
	for(int i=0;i<=n;i++) d[i] = INF ;
	d[s] = 0 ; 
	q.push({0,s}) ;
	while(q.size()){
		auto t = q.top() ; q.pop() ;
		int u = t.second ;
		if(vis[u]) continue ;// 出过队直接跳 
		vis[u] = 1 ;// 标记u已经出队
		for(auto ed : e[u]){
			int v = ed.v  , w = ed.w ;
			if(d[v] > d[u]+w){
				d[v] = d[u] + w ;
				pre[v] = u ;
				q.push({-d[v],v}) ;// 大根堆 
			}
		} 
	}
}

void dfs_path(int u){// 递归输出路径 
	if(u==s){printf("%d ",u);return ;}
	dfs_path(pre[u]) ;
	printf("%d ",u);
}

void dijkstra(int s){
    for(int i=0;i<=n;i++) d[i] = INF ;
    d[s] = 0 ;
	for(int i=1;i<n;i++){//枚举次数 
		int u = 0 ;// 相当于哨兵
		for(int j=1;j<=n;j++) 
			if(!vis[j]&&d[j]<d[u]) 
				u = j ;
 		vis[u] = 1 ;// 标记u以出圈
		for(auto ed : e[u]){// 枚举邻边 
			int v = ed.v , w = ed.w ;
			if(d[v]>d[u]+w)
				d[v] = d[u] + w ;
		}	
	}
}


int main(){
	cin >> n >> m >> s ;
	for(int i=0;i<m;i++){
		int a , b , c ; cin >> a >> b >> c ;
		e[a].push_back({b,c});
	}
	dijkstra_queue(s) ;
	for(int i=1;i<=n;i++) cout << d[i] << " " ;
	// dfs_path(4) ;
}

参考 : 

D02 最短路 Dijkstra 算法_哔哩哔哩_bilibili

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

K8s集群调度续章

目录 一、污点&#xff08;Taint&#xff09; 1、污点&#xff08;Taint&#xff09; 2、污点组成格式 3、当前taint effect支持如下三个选项&#xff1a; 4、查看node节点上的污点 5、设置污点 6、清除污点 7、示例一 查看pod状态&#xff0c;模拟驱逐node02上的pod …

选择快充时代下的理想充电器与电压诱骗芯片PW6606

随着科技的不断进步&#xff0c;我们的电子设备对于充电速度和效率的要求越来越高。在快充技术迅猛发展的今天&#xff0c;了解不同类型的充电器及其对应的快充协议&#xff0c;以及如何选择适合的电压诱骗芯片&#xff0c;对于提升充电体验和保障设备安全显得尤为重要。 一、快…

「代码厨房大揭秘:Python性能优化的烹饪秘籍!」

哈喽&#xff0c;我是阿佑&#xff0c;上篇咱们讲了 Socket 编程 —— 探索Python Socket编程&#xff0c;赋予你的网络应用隐形斗篷般的超能力&#xff01;从基础到实战&#xff0c;构建安全的聊天室和HTTP服务器&#xff0c;成为网络世界的守护者。加入我们&#xff0c;一起揭…

什么情况下JVM内存中的一个对象会被垃圾回收?

什么情况下JVM内存中的一个对象会被垃圾回收? 1、什么时候会触发垃圾回收?2、被哪些变量引用的对象是不能回收的?3、Java中对象不同的引用类型4、finalize()方法的作用1、什么时候会触发垃圾回收? 平时我们系统运行创建的对象都是优先分配在新生代里的,如图: 然后如果…

【JVM底层原理,JVM架构详解】

1. JVM简介 1.1 什么是JVM? JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 主流虚拟机: 虚拟机名称介绍HotSpotOracle/Sun JDK和OpenJDK都使用HotSPo…

【算法】位运算算法——丢失的数字

题解&#xff1a;丢失的数字(位运算算法) 目录 1.题目2.题解3.位运算异或4.总结 1.题目 题目链接&#xff1a;LINK 2.题解 哈希数组查漏高斯求和排序位运算异或… 3.位运算异或 class Solution { public:int missingNumber(vector<int>& nums) {int ret 0;for…

单调栈--

1.每日温度 那么单调栈的原理是什么呢&#xff1f;为什么时间复杂度是O(n)就可以找到每一个元素的右边第一个比它大的元素位置呢&#xff1f; 单调栈的本质是空间换时间&#xff0c;因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素高的元素&#xff0c;优点是整个数…

使用大模型LLM实现销售AI

想象一个场景&#xff0c;客户通过聊天窗口咨询一款产品。销售AI首先使用LLM解析客户的问题&#xff0c;然后通过智能代理查询数据库获取产品详细信息&#xff0c;并以自然而友好的方式回应客户。 在对话过程中&#xff0c;AI可以评估客户的兴趣&#xff0c;并主动提供促销信息…

【设计模式】JAVA Design Patterns——Curiously Recurring Template Pattern(奇异递归模板模式)

&#x1f50d;目的 允许派生组件从与派生类型兼容的基本组件继承某些功能。 &#x1f50d;解释 真实世界例子 对于正在策划赛事的综合格斗推广活动来说&#xff0c;确保在相同重量级的运动员之间组织比赛至关重要。这样可以防止体型明显不同的拳手之间的不匹配&#xff0c;例如…

Linux——多线程(一)

一、线程的概念 1.1线程概念 教材中的概念&#xff1a; (有问题?) 线程是进程内部的一个执行分支&#xff0c;线程是CPU调度的基本单位 之前我们讲的进程&#xff1a; 加载到内存中的程序&#x…

云易办springboot+vue后端

springbootvue云易办后端项目完成 一.创建项目 创建父项目&#xff1a;yeb&#xff0c; 使用spring Initializr&#xff0c;完成创建之后删除无用文件夹&#xff0c;作为父项目 添加packaging <packaging>pom</packaging>二.创建子模块&#xff1a;yeb-server …

PyCharm基本配置内容

如何更换 Python 解释器 输入一段代码点击运行后&#xff0c;画面下方有一个路径如图中框中所示&#xff1a; 上面的路径为虚拟路径&#xff0c;可以改为我们自己设置的路径 点击设置&#xff0c;选择settings 选择Project&#xff1a;y002———》Python Interpreter&#…

Clickhouse 嵌套数据类型总结—— Clickhouse 基础篇(三)

文章目录 创建嵌套类型的表插入读取数据在嵌套类型上使用数组函数 在 clickhouse 中存储嵌套类型的关键字是 Nested, 只支持一级嵌套。数据结构类似于在数据结构类似于在表的单元格里面嵌套“一张表格”&#xff0c;如下图所示&#xff1a; 嵌套类型是列存储&#xff0c;本质…

OWASP十大API漏洞解析:如何抵御Bot攻击?

新型数字经济中&#xff0c;API是物联网设备、Web和移动应用以及业务合作伙伴流程的入口点。然而&#xff0c;API也是犯罪分子的前门&#xff0c;许多人依靠Bot来发动攻击。对于安全团队来说&#xff0c;保护API并缓解Bot攻击至关重要。那么Bot在API攻击中处于怎样的地位&#…

【JVM】一次JVM内存泄露分析处理

一次内存泄露分析 背景情况 编写了一个大数据基础组件的可用性监控程序&#xff0c;采用Bootstrap监测端口的方式&#xff0c;使得方法常驻&#xff08;main线程常驻&#xff09;&#xff0c;通过一个调度线程ScheduledThreadPoolExecutor&#xff0c;定时的调动监测任务。 …

OTFS系统建模、通信性能分析、信道估计、模糊函数【附MATLAB代码】

文献来源&#xff1a;​微信公众号&#xff1a;EW Frontier OTFS简介 OTFS信道估计 % Clear command window, workspace variables, and close all figures clc; clear all; close all; ​ % Define Eb values in dB EbdB -10:2:10; ​ % Convert Eb values from dB to lin…

微软提出“Copilot+ PCs”构想,强调本地AI处理;OpenAI暂停ChatGPT语音功能因声音相似争议

&#x1f989; AI新闻 &#x1f680; 微软提出“Copilot PCs”构想&#xff0c;强调本地AI处理 摘要&#xff1a;在微软 Build 开发者前瞻大会上&#xff0c;CEO 萨蒂亚・纳德拉介绍了“Copilot PCs”&#xff0c;一种新类 Windows PC&#xff0c;需配备神经处理单元&#xf…

视频技术在智慧营业厅中的应用:AI识别与智能化转型

一、方案背景 随着信息技术的快速发展&#xff0c;图像和视频分析技术已广泛应用于各行各业&#xff0c;特别是在营业厅场景中&#xff0c;该技术能够有效提升服务质量、优化客户体验&#xff0c;并提高安全保障水平。TSINGSEE青犀智慧营业厅视频管理方案旨在探讨视频监控和视…

你真的懂firewalld吗?不妨看看我的这篇文章

一、firewalld简介 firewalld防火墙是Linux系统上的一种动态防火墙管理工具&#xff0c;它是Red Hat公司开发的&#xff0c;并在许多Linux发行版中被采用。相对于传统的静态防火墙规则&#xff0c;firewalld使用动态的方式来管理防火墙规则&#xff0c;可以更加灵活地适应不同…

ld链接文件

文章目录 1. sections缩写2. 链接脚本2.1 MEMORY&#xff08;内存命令&#xff09;2.1.1 作用2.1.2 格式 2.2 SECTIONS&#xff08;段命令&#xff09;2.2.1 作用2.2.2 格式 2.3 特殊符号含义2.4 通配符2.5 Eg 1. sections缩写 2. 链接脚本 https://www.cnblogs.com/jianhua19…