伪码:

    a. 初始化 dist[1] = 0, dist[i] = +inf  S:当前已经确定为最短距离的点b. for(int i = 1; i <= n; i ++){1. 寻找不在 S 中距离源点最近的点 t2. 将 t 加到 S 中3. 用 t 更新其他点的距离(dist[j] = min(dist[j], dist[t] + g[t][j]))}

Dijkstra算法的正确性证明:

定理: 最短路径的子路径仍然是最短路径(反证易得)

Dijkstra算法正确性证明: (rel是真实最短距离)

定理: Dijkstra算法中, 将顶点 u 添加到 S = {1,...,x} 中时, dist[u] = rel[u]

证: 假设 Dijkstra 算法, 将顶点 u 添加到 S 中时, dist[u] != rel[u]

由于 dist[u] 是 rel[u] 的上界, 故 dist[u] > rel[u]

应存在一条真实的最短路径 rel[u], 不妨设其为<1,...,x,y,...,u>,

其中边 (x, y) 横跨 <S, V-S>, x 属于 S, y 属于 V-S

对任意 x 属于 S, 有 rel[x] = dist[x]

1.<1,...,x,y>是<1,...,x,y,...,u>的子路径, 故:

rel[y] = rel[x] + w[x][y] = dist[x] + w[x][y]

2.算法对从 x 出发的所有边进行松弛操作, 故:

dist[y] <= dist[x] + w[x][y]

由于 dist 是 rel 的上界, 于是综合 1 与 2 可得 dist[y] = rel[y]

最短路径<1,...,x,y,...,u>中, y 出现在 u 之前, 故:

dist[u] > rel[u] >= rel[y] > dist[y]

由于 dist[u] > dist[y], u 不可能是下一个被添加的顶点, 故产生矛盾

算法步骤:

  1. 用一个 dist 数组保存源点到其余各个节点的距离,dist[i] 表示源点到节点 i 的距离。初始时,dist 数组的各个元素为无穷大。

用一个状态数组 state 记录是否找到了源点到该节点的最短距离,state[i] 如果为真,则表示找到了源点到节点 i 的最短距离,state[i] 如果为假,则表示源点到节点 i 的最短距离还没有找到。初始时,state 各个元素为假。

  1. 源点到源点的距离为 0。即dist[1] = 0。

  1. 遍历 dist 数组,找到一个节点,这个节点是:没有确定最短路径的节点中距离源点最近的点。假设该节点编号为 i。此时就找到了源点到该节点的最短距离,state[i] 置为 1。

  1. 遍历 i 所有可以到达的节点 j,如果 dist[j] 大于 dist[i] 加上 i -> j 的距离,即 dist[j] > dist[i] + w[i][j](w[i][j] 为 i -> j 的距离) ,则更新 dist[j] = dist[i] + w[i][j]。

  1. 重复 3 4 步骤,直到所有节点的状态都被置为 1。

  1. 此时 dist 数组中,就保存了源点到其余各个节点的最短距离。

AcWing 850. Dijkstra求最短路 I

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;const int N=510;int g[N][N];    //为稠密阵所以用邻接矩阵存储
int dist[N];    //用于记录每一个点距离第一个点的距离
bool st[N];     //用于记录该点的最短距离是否已经确定int n,m;int Dijkstra()
{memset(dist, 0x3f,sizeof dist);     //初始化距离  0x3f代表无限大dist[1]=0;  //第一个点到自身的距离为0for(int i=0;i<n;i++)      //有n个点所以要进行n次 迭代{int t=-1;       //t存储当前访问的点, 将t设置为-1 因为Dijkstra算法适用于不存在负权边的图for(int j=1;j<=n;j++)   //这里的j代表的是从1号点开始if(!st[j]&&(t==-1||dist[t]>dist[j]))     t=j;st[t]=true;   for(int j=1;j<=n;j++)           //依次更新每个点所到相邻的点路径值// 这里省略了一个if(!st[j]) 但是不影响,因为按照Dijkstra算法的操作顺序,先确定最短距离的点的距离已经比后确定的要小dist[j]=min(dist[j],dist[t]+g[t][j]);}if(dist[n]==0x3f3f3f3f) return -1;  //如果第n个点路径为无穷大即不存在最低路径return dist[n];
}
int main()
{cin>>n>>m;memset(g,0x3f,sizeof g);    //初始化图 因为是求最短路径//所以每个点初始为无限大while(m--){int x,y,z;cin>>x>>y>>z;g[x][y]=min(g[x][y],z);     //如果发生重边的情况则保留最短的一条边}cout<<Dijkstra()<<endl;return 0;
}

时间复杂度:寻找路径最短的点:O(n^2)、加入集合S:O(n)、更新距离:O(m)

总时间复杂度为O(n^2)

堆优化Dijkstra

a. 初始化 dist[1] = 0, dist[i] = +inf  S:当前已经确定为最短距离的点
b. for(int i = 1; i <= n; i ++){1. 寻找不在 S 中距离源点最近的点 t    ... 总共n^2次计算2. 将 t 加到 S 中        ... 总共n次计算3. 用 t 更新其他点的距离(dist[j] = min(dist[j], dist[t] + g[t][j]))   ... 总共m次计算(m条边)}

从时间复杂度分析可以看出,Dijkstra算法最慢的一步在于1.找不在S中的距离最近的点,为O(n^2),要想优化这一部分可以想到使用堆数据结构,于是第一步的时间复杂度就降为O(1)(总体时间复杂度降为O(n)),但是在堆中每次修改一个数的时间复杂度为O(logn),所以其第三步的时间复杂度就升为O(mlogn),所以整个算法的时间复杂度就优化为了O(mlogn)。

朴素版dijkstra适合稠密图(m > n),时间复杂度为O(n^2),用邻接矩阵来存。

堆优化版dijkstra适合稀疏图(m ~ n),时间复杂度为O(mlogn),用邻接表来存。

AcWing 850. Dijkstra求最短路 II

#include<iostream>
#include<cstring>
#include<queue>using namespace std;typedef pair<int, int> PII;const int N = 150010;// 稀疏图用邻接表来存
int h[N], e[N], ne[N], idx;
int w[N]; // 用来存权重
int dist[N];
bool st[N]; // 如果为true说明这个点的最短路径已经确定int n, m;void add(int x, int y, int c)
{// 有重边也不要紧,假设1->2有权重为2和3的边,再遍历到点1的时候2号点的距离会更新两次放入堆中// 这样堆中会有很多冗余的点,但是在弹出的时候还是会弹出最小值2+x(x为之前确定的最短路径),// 并标记st为true,所以下一次弹出3+x会continue不会向下执行。w[idx] = c;e[idx] = y;ne[idx] = h[x]; h[x] = idx++;
}int dijkstra()
{memset(dist, 0x3f, sizeof(dist));dist[1] = 0;priority_queue<PII, vector<PII>, greater<PII>> heap; // 定义一个小根堆// 这里heap中为什么要存pair呢,首先小根堆是根据距离来排的,所以有一个变量要是距离,// 其次在从堆中拿出来的时候要知道知道这个点是哪个点,不然怎么更新邻接点呢?所以第二个变量要存点。heap.push({ 0, 1 }); // 这个顺序不能倒,pair排序时是先根据first,再根据second,// 这里显然要根据距离排序while(heap.size()){PII k = heap.top(); // 取不在集合S中距离最短的点heap.pop();int ver = k.second, distance = k.first;if(st[ver]) continue;st[ver] = true;for(int i = h[ver]; i != -1; i = ne[i]){int j = e[i]; // i只是个下标,e中在存的是i这个下标对应的点。if(dist[j] > distance + w[i]){dist[j] = distance + w[i];heap.push({ dist[j], j });}}}if(dist[n] == 0x3f3f3f3f) return -1;else return dist[n];
}int main()
{memset(h, -1, sizeof(h));scanf("%d%d", &n, &m);while (m--){int x, y, c;scanf("%d%d%d", &x, &y, &c);add(x, y, c);}cout << dijkstra() << endl;return 0;
}

AcWing 1488. 最短距离

本题设计无向边,一条a--b的无向边等价于一条a->b的有向边加上一条b->a的有向边

此题是多源最短路问题,那么应该怎么将其转换成单源最短路问题以此应用Dijkstra呢?

我们只需要定义一个虚拟的节点,它到每一个源起点的距离都是0,然后再以这个虚拟节点作为起点即可

#include <iostream>
#include <cstring>
#include <queue>using namespace std;typedef pair<int, int> PII;const int N = 100010, M = 3 * N;
int h[N], w[M], e[M], ne[M], idx, dist[N];
int n, m;
bool st[N];void add(int a, int b, int c){w[idx] = c;e[idx] = b;ne[idx] = h[a];h[a] = idx++;
}void Dijkstra(){priority_queue<PII, vector<PII>, greater<PII>> heap;memset(dist, 0x3f, sizeof dist);dist[0] = 0;heap.push({0, 0});while(!heap.empty()){auto t = heap.top();heap.pop();int ver = t.second, distance = t.first;if(st[ver]) continue;st[ver] = true;for(int i = h[ver]; i != -1; i = ne[i]){int j = e[i];if(dist[j] > distance + w[i]){dist[j] = distance + w[i];heap.push({dist[j], j});}}}
}int main(){memset(h, -1, sizeof h);cin >> n >> m;while(m--){int a, b, c;cin >> a >> b >> c;add(a, b, c);add(b, a, c);}int k;cin >> k;while(k--){int x;cin >> x;add(0, x, 0);}Dijkstra();int q;cin >> q;while(q--){int y;cin >> y;printf("%d\n", dist[y]);}return 0;
}

AcWing:Dijkstra相关推荐

  1. 堆优化版dijkstra算法:AcWing 850. Dijkstra求最短路 II

    堆优化版dijkstra算法分析: 朴素版dijkstra的时间复杂度为O(n^2),主要瓶颈在于第1步的寻找全局最小值的过程. 可以用小根堆(C++STL priority_queue)对dist数 ...

  2. AcWing 850. Dijkstra求最短路 II

    原题链接:AcWing 850. Dijkstra求最短路 II 给定一个 n 个点 m 条边的有向图,图中可能存在 重边 和 自环 ,所有边权均为 非负值 . 请你求出 1 号点到 n 号点的最短距 ...

  3. AcWing 850. Dijkstra求最短路 II【最短路】【堆优化版Dijkstra】

    AcWing 850. Dijkstra求最短路 II 一.题目链接 二.题目分析 (一)算法标签 (二)解题思路 三.AC代码 四.其它题解 一.题目链接 AcWing 850. Dijkstra求 ...

  4. 图的单源最短路径:Dijkstra算法实现

    本文介绍的是图的非负权值的单源最短路径问题.问题的提出是,对于有权图D,t提供源点v,要找到从v到其他所有点的最短路径,即单源最短路径问题,在本文中,解决这一问题,是普遍比较熟悉的Dijkstra算法 ...

  5. 坐在马桶上看算法:Dijkstra最短路算法

                                                             [坐在马桶上看算法]算法7:Dijkstra最短路算法 上周我们介绍了神奇的只有五行的 ...

  6. 最短路径:Dijkstra算法和Floyd算法

    一.Dijkstra算法(单个顶点到其他顶点的最短距离) 定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层 ...

  7. VTK:Dijkstra 图形测地线路径用法实战

    VTK:Dijkstra 图形测地线路径用法实战 程序输出 程序完整源代码 程序输出 程序完整源代码 #include <vtkActor.h> #include <vtkCamer ...

  8. 分支限界发:Dijkstra算法

    从分支限界的角度来看Dijkstra算法: Dijkstra算法是基于贪心的广度优先搜索,也可以看成分支限界法,从分支限界的角度来看,Dijkstra算法看起来就更加清晰明了 代码实现: # ==== ...

  9. aes算法c语言实现_C语言实现常用数据结构:Dijkstra最短路径算法(第18篇)

    「今天是学习C语言第 161 天」 纸上学来终觉浅,绝知此事要躬行.-- 陆游「冬夜读书示子聿」#题外话算法学习重点是学习如何编程使用它. # Dijkstra算法 Dijkstra算法,中文译名迪杰 ...

最新文章

  1. python项目实战:获取本机所有IP地址的方法
  2. 项目: 写一个开头的界面 【c++ / c】
  3. Introduction for i-Teams
  4. CURL NDK 交叉编译
  5. T5: Text-to-Text Transfer Transformer 阅读笔记
  6. 收集一些 有效的算法
  7. 【网站】Bing每日壁纸API分享
  8. 95-190-444-源码-window-Trigger-EventTimeTrigger
  9. hdu 2896 AC自动机
  10. Java中try与catch的使用
  11. macOS 运行react项目
  12. HDU - 4287 Intelligent IME
  13. 实现百度地图marker平滑移动
  14. 机器人学之动力学笔记【9】—— 牛顿-欧拉 递推动力学方程
  15. 微信推送封面尺寸_微信公众平台图片尺寸是多少 如何设置
  16. 锚点的作用是什么?如何创建锚点?
  17. 基于Plupload的图片压缩上传
  18. airsim--client
  19. 基于ZigBee的城市道路除尘降温系统设计
  20. 同一网段和不同网段中的两台主机通信的过程

热门文章

  1. npm登录:忘记了用户名和密码,通过邮箱找回流程
  2. 病态!------沉沦的病态
  3. 工业机器人的控制算法
  4. 李嘉诚:成功创业要具备的五个要素
  5. 2013-04-26-成都华为实习生招聘上机笔试
  6. 马里兰大计算机专业学phd博士,亚利桑那州立大学计算机CS博士PHD全奖录取
  7. 海量数据相似数据查找方法(ANN):【高维稀疏向量的相似查找——MinHash, LSH, SimHash】【稠密向量的相似查找——Faiss、Annoy、ScaNN、Hnswlib】
  8. 关于Rigidbody,Collider和CharacterController三者之间的关系和用法的总结
  9. CSS Hank兼容浏览器的
  10. python❀序列结构