最短路径——Dijkstra算法以及二叉堆优化(含证明)

一般最短路径算法习惯性的分为两种:单源最短路径算法和全顶点之间最短路径。前者是计算出从一个点出发,到达所有其余可到达顶点的距离。后者是计算出图中所有点之间的路径距离。


单源最短路径

Dijkstra算法

思维

本质上是贪心的思想,声明一个数组dis来保存源点到各个顶点的最短距离和一个保存已经找到了最短路径的顶点的集合:S,原本的元素构成集合Q,初始时,原点 s 的路径权重被赋为 0 (dis[s] = 0)。若对于顶点 s 存在能直接到达的边(s,m),则把dis[m]设为w(s, m),同时把所有其他(s不能直接到达的)顶点的路径长度设为无穷大。初始时,集合S只有顶点s

然后,从dis数组选择最小值,则该值就是源点s到该值对应的顶点的最短路径,并且把该点加入到S中,此时完成一个顶点, 然后,我们需要看看新加入的顶点是否可以到达其他顶点并且看看通过该顶点到达其他点的路径长度是否比源点直接到达短,如果是,那么就替换这些顶点在dis中的值。 然后,又从dis中找出最小值,重复上述动作,直到S中包含了图的所有顶点。
但是很可惜,由于算法特性,一个点的距离确定后不会再改变,这里的确定不是指得到数值,而且该点被作为观察点观察后所以这个算法并不能处理带负权边的图。

但是可以利用该算法+优先队列来优化,优化后的算法打破了之前的一个点的距离确定后不会再改变的算法特性,更加类似SPFA,并且可以处理负权边。但个人觉得已经不能称作dijkstra算法了。


证明

这里给出一个命题:从集合Q中找到dis[k]最小的v,dis[k]即为源点到v的最短路径长度。
如果这个命题为真,dij的正确性就可以得证。

  • 证明:从开始利用算法取得一个v1,即dis[v1]是最小的,\(\forall\)v,dis[v]>dis[v1]。
    假设dis[v1]不是从源点到v1最短路径
    \(\exists\)v,使得dis[v]<dis[v1],与已知矛盾。
    得证。
  • 证明:已利用算法从Q中找到k个点,并确定了k个点的最短路径,此时再从Q中用算法找出一个vk+1,dis[vk+1]即为源点到vk+1最短路径。
    假设dis[vk+1不是源点到vk+1的最短路径长度。
    则设从源点到vk+1的最短路径经过的点的集合为V,dis为路径长度,切dis < dis[vk+1]。
    设V中最靠近vk+1且不属于S的点为vx,vx的后继点为vy
    。如果有向图中皆为正权边,则易得dis[vx] < dis[vy] <= dis。(vy = vk+1时等号成立)
    但又因为vx不属于S,则dis[vx] > dis,矛盾。
    得证。
  • 综上所述,命题得证。
  • 负权边的时候,dis[vx] < dis[vy]和dis[vx] > dis都不一定成立。故不得证。

举例演算

1329608-20181205220923542-618666981.png

集合S当前观察点udis[2]dis[3]dis[4]dis[5]dis[6]
1-12
1,221246
1,2,4415246
1,2,4,5515246
1,2,4,5,3315245
1,2,4,5,3,6615245

从结点1出发,1与2、4连通,确定(1,2),(1,4)的距离,其中到2的距离最短,再从观察点2出发,2与5、6连通,根据dis[u]+c[u][v]<dis[v]的判断关系出发,更新dis。接着再分别从观察点4,5,3,6出发更新dis,得到最终的结点1的单源最短路径。


代码实现

朴素dij算法,时间复杂度约为O(n2)

#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>using namespace std;const int maxn = 1000;
const int inf = 0x7fffffff;int n, m;
int e[maxn][maxn], dis[maxn];
int book[maxn];void dij(int s) {for (int i = 1; i <= n; i++) dis[i] = e[s][i];for (int i = 1; i <= n; i++) book[i] = 0;book[s] = 1;dis[s] = 0;for (int i = 1; i <= n - 1; i++) {int min = inf;int u;for (int j = 1; j <= n; j++) {if (book[j] == 0 && dis[j] < min) {min = dis[j];u = j;}}book[u] = 1;for (int v = 1; v <= n; v++) {if (e[u][v] < inf && book[v] == 0) {if (dis[v] > dis[u] + e[u][v]) {dis[v] = dis[u] + e[u][v];}}}}
}int main() {cin >> n >> m;for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {e[i][j] = inf;}}for (int i = 0; i < m; i++) {int u, v, w;cin >> u >> v >> w;e[u][v] = w;}int x;cin >> x;dij(x);for (int i = 1; i <= n; i++) {cout << dis[i] << " ";}return 0;
}

为了能够方便的寻找当前最小的dis作为观察点,可以利用优先队列最小堆来优化。同时利用初始化建表来节省寻找每个点的相邻点的过程。这里使用的是stl中的优先队列,底层是heap实现的,应该是二叉堆,所以时间复杂度应该是O((m+n)logn),如果是使用斐波那契堆,可以到O(nlogn)。

#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>using namespace std;const int MAX = 1000;int h[MAX * 2], to[MAX * 2], nxt[MAX * 2], co[MAX * 2], dis[MAX], k = 0, n, m;
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > que;void insert(int u,int v,int c) {nxt[++k] = h[u];h[u] = k;to[k] = v;co[k] = c;nxt[++k] = h[v];h[v] = k;to[k] = u;co[k] = c;
}void dij(int s) {for (int i = 0; i < MAX; i++) dis[i] = 0x7FFFFFFF;dis[s] = 0;que.push(make_pair(dis[s], s));while (!que.empty()) {pair<int, int> u = que.top();que.pop();if (dis[u.second] < u.first) continue;for (int i = h[u.second]; i; i = nxt[i]) {if (dis[to[i]] > dis[u.second] + co[i]) {dis[to[i]] = dis[u.second] + co[i];que.push(make_pair(dis[to[i]], to[i]));}}}
}int main() {cin >> n >> m;memset(h, 0, sizeof(h));int u, v, c;for (int i = 0; i < m; i++) {cin >> u >> v >> c;insert(u, v, c);}int x;cin >> x;dij(x);for (int i = 1; i <= n; i++) {if (dis[i] > 100000) cout << "none" << " ";else cout << dis[i] << " ";}cout << endl;return 0;
}

转载于:https://www.cnblogs.com/pullself/p/10073785.html

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

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

相关文章

linux shmget shmctl

shmgetint shmget(key_t key, size_t size, int flag);key: 标识符的规则size:共享存储段的字节数flag:读写的权限返回值&#xff1a;成功返回共享存储的id&#xff0c;失败返回-1key_t key----------------------------------------------- key标识共享内存的键值: 0/IPC_P…

java控制台输入输出总结

一、控制台输入&#xff1a; 1.最常用&#xff1a;Scanner public static void main(String[] args) { System.out.println("请输入数据:"); Scanner scan new Scanner(System.in); String read scan.nextLine(); System.out.println("输入的数据为:"…

伯克利开源工具库RLib现已支持大规模多智能体强化学习

AI前线导读&#xff1a;近日&#xff0c;UC伯克利的研究团队RISELab在其Github的项目Ray Rlib 0.6.0中添加了面向多智能体强化学习&#xff08;multi-agent Reinforcement Learning&#xff09;的支持。本文由团队成员Eric Liang首发于RISELab团队主页&#xff0c;AI前线翻译整…

相机电子快门和机械快门有什么区别

https://zhidao.baidu.com/question/9178007.html

Long

而由于javascript数字的最大值2的53次方-1&#xff0c;以及PHP的数字处理能力&#xff0c;比如number_format(9027199254740993, 0, , )转载于:https://www.cnblogs.com/sfsdst/p/6734083.html

操作系统实验以及课程设计

趁没人&#xff0c;当个小白来偷偷摸摸补一下操作系统的课程&#xff0c;羞反正操作系统断断续续的看了一点了&#xff0c;主要是偏linux的。FreeBSD的实现&#xff0c;操作系统概念&#xff0c;30天自制操作系统等。Linux的话命令用的还行&#xff0c;没有很深入的搞。看操作系…

关于星光级和低照度你了解多少?

http://www.tpy888.cn/news/201607/22/89214.html

AI界的妖风

最近一篇文章https://zhuanlan.zhihu.com/p/50948707深度学习碰上古文献&#xff0c;西南大学提出基于CNN的古彝文识别方法 我预计不久之后就会出现一个现象&#xff1a;不光有彝族文字识别&#xff0c;还有蒙文识别&#xff0c;藏文识别&#xff0c;苗文识别 然后各位教授一起…

poj1936

非连续子串匹配题&#xff0c;直接模拟 /** \brief poj 1936** \param date 2014/8/5* \param state AC* \return memory 804k time 0ms**/#include <iostream> #include <fstream> #include <cstring>using namespace std;const int MAXN100000; char s[MAX…

Process和ProcessBuilder入门【原】

ProcessBuilder优点 ProcessBuilder(XXX).start()和Runtime.exec(XXX)功能相同,主要优点在使用过程中感受有: 前者是jdk1.5后的新方式配置环境变量时更优雅对当前目录的控制也更合理错误流重定向特别方便 进程控制更简洁ProcessTool.java package test;import java.io.Buffered…

如何简单理解光圈大小对手机摄影的影响?

你&#xff0c;准备好参加今夏的朋友圈摄影大赛了吗&#xff1f; 现在的天气有多热&#xff0c;谁出门谁知道&#xff01;出去玩还要背一台单反&#xff0c;绝对可以说是一种折磨了。但是&#xff0c;如果你拥有一台大光圈的手机&#xff0c;一样可以在朋友圈脱颖而出。 那么…

基于centos6.7的docker私有仓库搭建

2019独角兽企业重金招聘Python工程师标准>>> 1 仓库配置https认证 cd /etc/docker/ mkdir certs [rootdocker01 docker]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout certs/docker01.key -x509 -days 365 -out certs/docker01.crt 填好相应的简称及email…

第十周软件工程作业-每周例行报告

一、PSP T名称C内容ST开始时间ED结束时间中断时间/min实际时间/min会议第一次Scrum会议11月17日16:0011月17日16:30030第二次Scrum会议11月18日15:0011月18日15:30030第三次Scrum会议11月19日17:0011月19日17:30030第四次Scrum会议11月20日11:3511月20日12:15040第五次Scrum会议…

卷帘快门与全局快门的区别

https://wenku.baidu.com/view/2f0c8da0ce2f0066f5332283.html

MAVEN下载和安装

1.maven的下载 下载链接http://maven.apache.org/download.cgi从该网站下载最新版本 2.maven的安装 电脑上需要安装JDK环境&#xff0c;需要安装JDK7以上的版本。下载之后进行解压&#xff0c;将maven解压到不含中文和空格的一个目录 maven目录结构bin目录&#xff1a;mvn.bat、…

洛谷 P3391 【模板】文艺平衡树

题目背景 这是一道经典的Splay模板题——文艺平衡树。 题目描述 您需要写一种数据结构&#xff0c;来维护一个有序数列&#xff0c;其中需要提供以下操作&#xff1a;翻转一个区间&#xff0c;例如原有序序列是5 4 3 2 1&#xff0c;翻转区间是[2,4]的话&#xff0c;结果是5 2 …

CCD/CMOS靶面尺寸型号标准

传感器尺寸指的是感光器对角线尺寸&#xff0c;1/1.7英寸&#xff08;14.8毫米&#xff0d;&#xff0d;导向管尺寸&#xff09;大于1/2.3英寸&#xff08;10.95毫米&#xff0d;&#xff0d;&#xff0d;导向管尺寸&#xff09;.采用同种技术水平的感光器&#xff0c;肯定是单…

分布式学习基础知识

网络通讯&#xff0c;网络是分布式的基础&#xff0c;对分布式的理解建立在对网络的理解上&#xff0c;包括&#xff1a; OSI模型的7层TCP/IP&#xff0c;DNS&#xff0c;NATHTTP&#xff0c;SPDY/HTTP2Telnet网络编程&#xff0c;是通过程序在多个主机之间通信。包括&#xff…

django中FastDFS客户端与自定义文件存储系统

什么是FastDFSFastDFS 是用 c 语言编写的一款开源的分布式文件系统。FastDFS 为互联网量身定制&#xff0c; 充分考虑了冗余备份、负载均衡、线性扩容等机制&#xff0c;并注重高可用、高性能等指标&#xff0c;使用 FastDFS 很容易搭建一套高性能的文件服务器集群提供文件上传…

新近碰到的病毒(TR.Spy.Babonock.A)

先来段Microsoft的说明&#xff1a; Worm:Win32/Babonock.A Alert level: Severe Detected with Windows Defender Antivirus Also detected as:Worm/Win32.AutoIt (AhnLab)Trojan-Spy.Win32.AutoIt.p (Kaspersky)Worm/Autoit.ANVE (AVG)TR/Spy.Babonock.A (Avira)Win32/Autoit…