龙空技术网

「洛谷日报第31期」dijkstra详解

洛谷科技 182

前言:

而今你们对“dijkstra算法步骤例题表格”大致比较关注,小伙伴们都需要知道一些“dijkstra算法步骤例题表格”的相关文章。那么小编也在网络上网罗了一些有关“dijkstra算法步骤例题表格””的相关内容,希望姐妹们能喜欢,我们快快来学习一下吧!

前言

SPFA 算法由于它上限 O(NM) = O(VE) 的时间复杂度,被卡掉的几率很大.在算法竞赛中,我们需要一个更稳定的算法: dijkstra .

什么是 dijkstra ?

dijkstra 是一种单源最短路径算法,时间复杂度上限为 O(n^2) (朴素),在实际应用中较为稳定 ; 加上堆优化之后更是具有 O((n+m)\log_{2}n) 的时间复杂度,在稠密图中有不俗的表现.

dijkstra 的原理/流程?

dijkstra 本质上的思想是贪心,它只适用于不含负权边的图.

我们把点分成两类,一类是已经确定最短路径的点,称为"白点",另一类是未确定最短路径的点,称为"蓝点"

dijkstra 的流程如下 :

1. 初始化 dis[start] = 0, 其余节点的 dis 值为无穷大.

2. 找一个 dis 值最小的蓝点 x, 把节点 x 变成白点.

3. 遍历 x 的所有出边 (x,y,z), 若 dis[y] > dis[x] + z, 则令 dis[y] = dis[x] + z

4. 重复 2,3 两步,直到所有点都成为白点 .

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

dijkstra 为什么是正确的

当所有边长都是非负数的时候,全局最小值不可能再被其他节点更新.所以在第 2 步中找出的蓝点 x 必然满足 :dis[x] 已经是起点到 x 的最短路径 . 我们不断选择全局最小值进行标记和拓展,最终可以得到起点到每个节点的最短路径的长度

图解

(令 start = 1 )

开始时我们把 dis[start] 初始化为 0 ,其余点初始化为 inf

第一轮循环找到 dis 值最小的点 1 ,将 1 变成白点,对所有与 1 相连的蓝点的 dis 值进行修改,使得 dis[2]=2,dis[3]=4,dis[4]=7

第二轮循环找到 dis 值最小的点 2 ,将 2 变成白点,对所有与 2 相连的蓝点的 dis 值进行修改,使得 dis[3]=3,dis[5]=4

第三轮循环找到 dis 值最小的点 3 ,将 3 变成白点,对所有与 2 相连的蓝点的 dis 值进行修改,使得 dis[4]=4

接下来两轮循环分别将 4,5 设为白点,算法结束,求出所有点的最短路径

时间复杂度 O(n^2)

为什么 dijkstra 不能处理有负权边的情况?

我们来看下面这张图

2 到 3 的边权为 -4 ,显然从 1 到 3 的最短路径为 -2 (1->2->3). 但在循环开始时程序会找到当前 dis 值最小的点 3 ,并标记它为白点.

这时的 dis[3]=1, 然而 1 并不是起点到 3 的最短路径.因为 3 已经被标为白点,所以 dis[3] 不会再被修改了.我们在边权存在负数的情况下得到了错误的答案.

dijkstra 的堆优化?

观察 dijkstra 的流程,发现步骤 2 可以优化

怎么优化呢?

我会zkw线段树!我会斐波那契堆!

我会堆!

我们可以用堆对 dis 数组进行维护,用 O(\log_{2}n) 的时间取出堆顶元素并删除,用 O(\log_{2}n) 遍历每条边,总复杂度 O((n+m)\log_{2}n)

范例代码:

例题

入门模板:P3371

进阶模板:P4779

其余例题请右转洛谷题库,搜索"最短路"

后记

本文部分内容摘自李煜东《算法竞赛进阶指南》和《信息学竞赛一本通》

友情提示:正权图请使用 dijkstra 算法,负权图请使用 SPFA 算法

感谢洛谷各位管理员提供的平台

本文发布于洛谷日报,特约作者:little_sun

原文地址:

标签: #dijkstra算法步骤例题表格