前言
这是之前写过的一篇 D i j k s t r a Dijkstra Dijkstra算法博客的重置版,最近正好在复习,发现了一些事实错误(我菜爆了),再加上当时用的是富文本编辑器写的,整体排版不太好看,于是干脆推到重写,以下是原文前言部分:
最近一直忙,没有时间写算法博客(其实是去水数据结构去了),今天睡前写一篇图论的基础算法吧,叫 D i j k s t r a Dijkstra Dijkstra,是由荷兰计算机科学家 E . W . D i j k s t r a E.W.Dijkstra E.W.Dijkstra于1959年提出的,因此叫 D i j k s t r a Dijkstra Dijkstra算法.是求从一个源点到其余各顶点的最短路径算法,即单源最短路算法,解决的是图论中最短路径问题.
原理
对于一个有 m m m条边, n n n个顶点的图,我们先定义如下描述,以表示一个图的某些关系:
源点 s t st st,表示算法所求最短路的出发顶点;
点集 V V V,表示图中所有点构成的集合,其中 ∣ V ∣ = n |V| = n ∣V∣=n;
边集 E E E,表示途中所有边构成的集合,其中 ∣ E ∣ = m |E| = m ∣E∣=m;
数组 d i s [ ] dis[] dis[],表示源点 s t st st到其余点的最短路径,数组大小为 n n n;
三元组 < u , v , w > <u,v,w> <u,v,w>,表示有一条从 u u u到 v v v,权值为 w w w的边,即 u → v = w u \to v = w u→v=w;
我们选择一个源点 s t st st,求它到其余所有点的最短路径,算法描述如下:
- 初始化: 将源点到的所有顶点的最短距离设为 + ∞ +\infin +∞,到自身为 0 0 0: ∀ i ∈ V , d i s [ i ] → + ∞ , d i s [ s t ] = 0 \forall i \in V, dis[i] \to + \infin, dis[st] = 0 ∀i∈V,dis[i]→+∞,dis[st]=0.
- 找点松弛边: 寻找一个离源点 s t st st最近的且未使用过的点 i i i,以该点为中间点松弛源点 s t st st到其他点的最短路径,松弛操作描述如下: ∀ < i , v , w > ∈ E , d i s [ v ] = m i n ( d i s [ v ] , d i s [ i ] + w ) \forall <i,v,w> \in E,dis[v] = min(dis[v],dis[i] + w) ∀<i,v,w>∈E,dis[v]=min(dis[v],dis[i]+w),标记 i i i为用过的点.
- 重复2,直到所有点都用过(松弛进行了 n − 1 n-1 n−1次).
在算法描述里提到了松弛这个概念,那么,什么是松弛呢?
所谓松弛,即寻找一个顶点 t t t,使得从 s t → e st \to e st→e的最短路长度能通过 t t t中转变成 s t → t → e st \to t \to e st→t→e,且长度缩短,那么我们就说 s t → e st \to e st→e的最短路通过t这个点松弛成功.比如 1 → 2 1 \to 2 1→2有长为 9 9 9的路径, 1 → 3 1 \to 3 1→3有长为 1 1 1的路径, 3 → 2 3 \to 2 3→2有长为 3 3 3的路径,则通过 3 3 3松弛