图论算法(四)Dijkstra算法
2021-04-23 00:29
标签:赋值 通过 set log 优先队列 打包 出发点 不能 pair PS:因为这两天忙着写GTMD sagment_tree,所以博客可能是sag+图论混搭着来,另外sag的基本知识就懒得整理了…… 以下,我们用dis[n]表示1->n的最短路径长度,vis[n]表示n号节点有没有被访问过 Dijkstra算法基于贪心的思想,每次从dis[ ]数组中取出一个dis[ ]值最小的节点x,把vis[x]标记为true,同时用这个点的所有连边去更新与x相连的点y的dis[ ]值 其中,更新的条件是这样的:(dis[y]=min(dis[y],dis[x]+x->y)),也就是y的更新后最短路值=min(当前y的最短路值,x的最短路值+x->y的边权) 每次松弛操作,使得1->x,1->y,x->y这三条边满足三角形不等式,扫完x点的所有边之后,此时,没有被访问过且dis值最小的点的最短路就已经被确定了 重复取出dis[ ]值最小节点的操作,更新y的值,直到vis[ ]全部为true,也就是所有节点都被访问过。此时,dis数组中dis[i]就是1->i的最短路 下面给出dijkstra的证明方法(拓展内容):https://www.cnblogs.com/jiangshaoyin/p/9954937.html 另外,出现负边权的时候,dijkstra算法不能正常工作 还记得吗?前面我们提到了在松弛之前,有一个取出dis数组中最小值的操作,对吧? 这个操作的复杂度是O(n)的,再加上用来更新的for循环,整体复杂度就变成了O(n2)的 显然,O(n2)的复杂度还不够快,那么考虑怎么优化? 很容易想到数据结构对吧?这里我们可以使用一个小根堆来实时维护dis中的最小值和这个最小值所对应的编号,取得最小值所在节点编号的复杂度降低到了O(logn) 这样做,使得整体复杂度降低到了O((m+n)logn)(其中m是边数,n是点数) 问题又来了,手写小根堆优化会导致码量的暴增,而且容易出错,我们迫切的需要一种简洁,易实现的代码 当然不,STL中queue头文件为我们提供了priority_queue这样一个大根堆,我们想想,可不可以利用这个大根堆呢? 想要利用priority_queue,首先要解决两个问题: 1、我们需要存下两个变量,一个是dis数组中的值,当做第一关键字入堆,还有这个dis值对应的节点编号,这需要开一个结构体 开结构体又导致另一个问题——priority-queue不知道以谁为关键字入堆排序 2、把优先队列的大根堆形式变成小根堆 “做到这些,需要一些奇技淫巧” ——By 一扶苏一 2020.6.28 解决方法一:重载‘
我们重载‘
代码如下: 这里我们重载了‘’自然就是返回sp小的),一次性解决了上面的两个问题 解决方法二:C++内置pair二元组 我们可以使用C++内置的二元组pair来解决关键字的问题,因为pair默认以第一维为第一关键字 C++内置pair基本用法如下代码: 另外,把大根堆变成小根堆,我们可以在入堆的时候把dis值取反(只是在堆中是相反数,dis值保持原样),这样我们就用pair解决了这两个问题 洛谷P4779、洛谷P3371 PS:P4779板子粘上去就过,P3371板子粘上去再加个231的特判又AC了…… P4779传送门:https://www.luogu.com.cn/problem/P4779 P3371传送门:https://www.luogu.com.cn/problem/P3371 “不要光刷题意相同的题,不要光刷板子题!”——By 一扶苏一 2020.7.2 所以,建议做完板子题之后,多找找最短路的题目,斟酌一下SPFA、Dijkstra,Floyd用哪个,具体怎么实现,快速完成代码,最好做到不要出错 到此,图论最短路算法,终于完结。。。 图论算法(四)Dijkstra算法 标签:赋值 通过 set log 优先队列 打包 出发点 不能 pair 原文地址:https://www.cnblogs.com/zaza-zt/p/13254054.html最短路算法(三)Dijkstra算法
Part 1:Dijkstra算法基本信息
证明可以仅做了解,毕竟OI不是证明能力大赛Part 2:优化Dijkstra算法
struct node{
int sp,num;
bool friend operator b.sp;
priority_queue
(PS:pair以第二维为第二关键字,但是这里第二关键字我们并不关心,因为不会影响到dijkstra的结果)#include
Part 3:Dijkstra 模板代码
仅供参考
#include
板子题: