dijkstra_堆优化(内附dijkstra原理解释)
P4779 【模板】单源最短路径(标准版)
题目背景
2018 年 7 月 19 日,某位同学在 NOI Day 1 T1 归程 一题里非常熟练地使用了一个广为人知的算法求最短路。
然后呢?
$100 \rightarrow 60$;
$\text{Ag} \rightarrow \text{Cu}$;
最终,他因此没能与理想的大学达成契约。
小 F 衷心祝愿大家不再重蹈覆辙。
题目描述
给定一个 $n$ 个点,$m$ 条有向边的带非负权图,请你计算从 $s$ 出发,到每个点的距离。
数据保证你能从 $s$ 出发到任意点。
输入格式
第一行为三个正整数 $n, m, s$。
第二行起 $m$ 行,每行三个非负整数 $u_i, v_i, w_i$,表示从 $u_i$ 到 $v_i$ 有一条权值为 $w_i$ 的有向边。
输出格式
输出一行 $n$ 个空格分隔的非负整数,表示 $s$ 到每个点的距离。
输入输出样例 #1
输入 #1
1 | 4 6 1 |
输出 #1
1 | 0 2 4 3 |
说明/提示
样例解释请参考 数据随机的模板题。
$1 \leq n \leq 10^5$;
$1 \leq m \leq 2\times 10^5$;
$s = 1$;
$1 \leq u_i, v_i\leq n$;
$0 \leq w_i \leq 10 ^ 9$,
$0 \leq \sum w_i \leq 10 ^ 9$。
本题数据可能会持续更新,但不会重测,望周知。
dijkstra算法详解
什么是dijkstra?
- dijkstra是一种单源最短路径算法,时间复杂度上限为O(n^2)(朴素),在实际应用中较为稳定;加上堆优化之后更是具有O((n+m)logn)的时间复杂度,在稠密图中有不俗的表现.(适用于不含负权边的图)
dijkstra流程
- 把点分为已经确定最短路的黑点和未确定最短路的白点
- 用dis数组表示该点距起点的距离
- 初始化:dis[start] = 0,其余全标成INF
- 找出所有白点中dis最小的点v,将它标成黑点
- 用v来更新所有它邻接点u的dis,
dis[u] = min(dis[u], dis[v] + len(v->u))
- 再重复4, 5直到所有点都被标成黑点
dijkstra的解释
- 到达一个白点s的可能情况分为以下两种:
- 从黑点到达
- 先到其他白点,再到达它
- 而当s的dis已经成为所有白点中最小时,它的dis不再可能被第二种情况更新(在所有权值非负的情况下),因为先到任何一个其他白点的代价都比直接到它更大
- 而这时留在场上的白点全都是可能被s更新的点,所以再用它来更新一遍dis
- 我们可以发现dijkstra的本质思想就是==贪心==,它只适用于不含负权边的图
dijkstra的堆优化
- 观察dijkstra的流程,易知查找最小dis的步骤可使用priority_queue优化
- 我们可以用堆对dis数组进行维护,用O(logn)的时间取出堆顶元素并删除,用O(logn)遍历每条边,总复杂度O((n+m)logn)
代码示例与注解
1 |
|
补充说明
- 为便于寻找邻接点的操作 本例使用邻接表储存图
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Spring Garden!