最短路算法(三)Dijkstra算法

PS:因为这两天忙着写GTMD segment_tree,所以博客可能是seg+图论混搭着来,另外segment_tree的基本知识就懒得整理了……

Part 1:Dijkstra算法基本信息

以下,我们用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

证明可以仅做了解,毕竟OI不是证明能力大赛

另外,出现负边权的时候,dijkstra算法不能正常工作

Part 2:优化Dijkstra算法

还记得吗?前面我们提到了在松弛之前,有一个取出dis数组中最小值的操作,对吧?

这个操作的复杂度是\(O(n)\)的,再加上用来更新的for循环,整体复杂度就变成了\(O(n\)\(2\)\()\)的

显然,\(O(n\)\(2\)\()\)的复杂度还不够快,那么考虑怎么优化?

很容易想到数据结构对吧?这里我们可以使用一个小根堆来实时维护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

解决方法一:重载‘<’运算符

我们重载‘<’号运算符,让priority_queue一dis值为第一关键字的同时,把原来的大根堆变成小根堆

代码如下:

struct node{
int sp,num;
bool friend operator < (node a,node b){
return a.sp>b.sp;
priority_queue<node>q;
}
}

这里我们重载了‘<’运算符(PS:对于所有C++STL,需要比较大小的,只要求我们重载‘<’运算符,因为通过‘<’号的定义,可以推至所有别的符号的定义,比如,这里我把‘<’重载为返回sp大的,那么‘>’自然就是返回sp小的),一次性解决了上面的两个问题

解决方法二:C++内置pair二元组

我们可以使用C++内置的二元组pair来解决关键字的问题,因为pair默认以第一维为第一关键字

(PS:pair以第二维为第二关键字,但是这里第二关键字我们并不关心,因为不会影响到dijkstra的结果)

C++内置pair基本用法如下代码:

#include<cstdio>
#include<iostream>
using namespace std;
int main(){
pair<int,int>x;//声明二元组的第一维,第二维的数据类型和二元组名字
x=make_pair(1,2);//给二元组赋值,先把“1,2”用make_pair()打包,然后分别赋值给第一维和第二维
int a=x.first,b=x.second;//分别返回二元组x的第一维,第二维
printf("%d %d",a,b);
}

另外,把大根堆变成小根堆,我们可以在入堆的时候把dis值取反(只是在堆中是相反数,dis值保持原样),这样我们就用pair解决了这两个问题

Part 3:Dijkstra 模板代码 仅供参考

#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int N=100010,M=500010;
int head[N],ver[M],edge[M],Next[M],d[N];
bool v[N];
int n,m,tot,s;
priority_queue< pair< int,int > >q;//包含pair的优先队列
void add(int x,int y,int z){//链式前向星存图
ver[++tot]=y;
edge[tot]=z;
Next[tot]=head[x];
head[x]=tot;
}
void dijkstra(int x){
memset(d,0x3f,sizeof(d));//把距离初始化无限大
memset(v,0,sizeof(v));//初始化没有访问过
d[x]=0;//初始节点距离为0
q.push((make_pair(0,x)));//初始节点入堆
while(q.size()!=0){
int x=q.top().second;//访问第二维,也就是节点编号
q.pop();//弹出
if(v[x]==1) continue;//如果走过了,直接进行下一次
v[x]=1;//标记访问过
for(int i=head[x];i;i=Next[i]){//链式前向星访问连边
int y=ver[i],z=edge[i];
if(d[y]>d[x]+z){//松弛
d[y]=d[x]+z;//更新最短路
q.push(make_pair(-d[y],y));//把d[y]的相反数入堆,大根堆变小根堆
}
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&s);//n点m边,s出发点
for(int i=1,x,y,z;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);//读边
add(x,y,z);
}
dijkstra(s);//求单元最短路
for(int i=1;i<=n;i++)
printf("%d ",d[i]);//输出到每一个节点的距离,如果到不了该节点,输出0x3f3f3f3f
return 0;
}

板子题:

洛谷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算法的更多相关文章

  1. 数据结构与算法系列研究七——图、prim算法、dijkstra算法

    图.prim算法.dijkstra算法 1. 图的定义 图(Graph)可以简单表示为G=<V, E>,其中V称为顶点(vertex)集合,E称为边(edge)集合.图论中的图(graph ...

  2. 算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法

    一.名称 动态规划法应用 二.目的 1.贪婪技术的基本思想: 2.学会运用贪婪技术解决实际设计应用中碰到的问题. 三.要求 1.实现基于贪婪技术思想的Prim算法: 2.实现基于贪婪技术思想的Dijk ...

  3. 最短路径算法(Dijkstra算法、Floyd-Warshall算法)

    最短路径算法具体的形式包括: 确定起点的最短路径问题:即已知起始结点,求最短路径的问题.适合使用Dijkstra算法. 确定终点的最短路径问题:即已知终结结点,求最短路径的问题.在无向图中,该问题与确 ...

  4. 分布式共识算法 (四) BTF算法(区块链使用)

    系列目录 分布式共识算法 (一) 背景 分布式共识算法 (二) Paxos算法 分布式共识算法 (三) Raft算法 分布式共识算法 (四) BTF算法 一.引子 前面介绍的算法,无论是 Paxos ...

  5. 图论基础之Dijkstra算法的初探

         图论,顾名思义就是有图有论.        图:由点"Vertex"和边"Edge "组成,且图分为有向图和无向图(本文讨论有向图),之前做毕业设计的 ...

  6. 图论-最短路径 2.Dijkstra算法O (N2)

    2.Dijkstra算法O (N2) 用来计算从一个点到其他所有点的最短路径的算法,是一种单源最短路径算法.也就是说,只能计算起点只有一个的情况. Dijkstra的时间复杂度是O (N2),它不能处 ...

  7. 2019中山纪念中学夏令营-Day14 图论初步【dijkstra算法求最短路】

    Dijkstra是我学会的第一个最短路算法,为什么不先去学SPFA呢?因为我在luogu上翻到了一张比较神奇的图: 关于SPFA -它死了 以及网上还有各位大佬的经验告诉我:SPFA这玩意很容易被卡. ...

  8. 最短路径算法之Dijkstra算法(java实现)

    前言 Dijkstra算法是最短路径算法中为人熟知的一种,是单起点全路径算法.该算法被称为是“贪心算法”的成功典范.本文接下来将尝试以最通俗的语言来介绍这个伟大的算法,并赋予java实现代码. 一.知 ...

  9. 最短路算法之Dijkstra算法通俗解释

    Dijkstra算法 说明:求解从起点到任意点的最短距离,注意该算法应用于没有负边的图. 来,看图. 用邻接矩阵表示 int[][] m = { {0, 0, 0, 0, 0, 0}, {0, 0, ...

  10. 最短路经算法简介(Dijkstra算法,A*算法,D*算法)

    据 Drew 所知最短路经算法现在重要的应用有计算机网络路由算法,机器人探路,交通路线导航,人工智能,游戏设计等等.美国火星探测器核心的寻路算法就是采用的D*(D Star)算法. 最短路经计算分静态 ...

随机推荐

  1. p70_域名解析系统DNS

    一.DNS作用 二.域名 www.cskaoyan.com. www 三级域名 cskaoyan 二级域名 com 顶级域名 三.域名服务器 根域名服务器:知道所有顶级域名服务器的域名和ip地址 顶级 ...

  2. 【几何+模拟】二次元变换 计蒜客 - T3213

    题目 aslky 有一个 n×n 的矩形,每个位置上都有一个数,有 q 次操作,每次他会让你上下翻转 (UD),左右反转 (LR),顺时针旋转 90∘(SZ),逆时针旋转 90∘(NZ),请你输出最后 ...

  3. ElementUI 级联选择框 设置最后一级可选及相关问题解决

    在使用 elementUI 的 el-cascader 级联选择框进行省市联动效果时,有这么一个需求:该级联选择框一共有三级结构分别为国家-省份-城市,国家和省份为必选项,城市为可选项.具体实现如下: ...

  4. docker 入门教程(5)——总结与学习资料

    总结 registry:docker镜像仓库,集中存储和管理镜像,类似maven仓库. image:docker镜像,定义容器运行的文件和参数,可以看作是面向对象编程的类. container:doc ...

  5. JavaSE基础知识之修饰符和使用场景,你真的了解嘛

    修饰符的作用是啥? 用来定义类.方法或者变量的访问权限 两大类 访问修饰符 限定类.属性或方法是否可以被程序里的其他部分访问和调用的修饰符 private<default<protecte ...

  6. CentOS7 firewalld docker 端口映射问题,firewall开放端口后,还是不能访问,解决方案

    # 宿主机ip: 192.168.91.19 docker run -itd --name tomcat -p 8080:8080 tomcat /usr/local/apache-tomcat-9. ...

  7. Flutter学习笔记(41)--自定义Dialog实现版本更新弹窗

    如需转载,请注明出处:Flutter学习笔记(41)--自定义Dialog实现版本更新弹窗 功能点: 1.更新弹窗UI 2.强更与非强更且别控制 3.屏蔽物理返回键(因为强更的时候点击返回键,弹窗会消 ...

  8. Vue开启gzip压缩文件

    在你的项目使用了Vue的路由懒加载.Vue使用CDN引用项目组件,减少项目体积 后,还是觉得项目加载速度慢,效果不尽如人意的时候,还有一个“瘦身项目”可以完成,那就是利用nginx和webpack来使 ...

  9. Java中的锁机制

    1.在Java中锁的分类 其实就是按照锁的特性分类的 公平锁,非公平锁 可重入锁 独享锁,共享锁 互斥锁,读写锁 乐观锁,悲观锁 分段锁 偏向锁,轻量级锁,重量级锁 自旋锁 相关资料:思维导图 使用场 ...

  10. c++ string类find总结

    c++ string类的find:1.find string s = "My cat's breath smells like cat food."; int a=s.find(& ...