SPFA和Dijkstra分别适用于什么方面呢?

Posted biran007

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPFA和Dijkstra分别适用于什么方面呢?相关的知识,希望对你有一定的参考价值。

 

heap+dijkstra与SPFA都是单源最短路的高效算法,到底谁比较快一直各有各的说法。于是心血来潮自己测试了下。

测试工具:cena 0.6

系统: windows vista

CPU: T2130, 1.86Ghz

 

所有程序中,图用相同格式存储,输入,输出,数据都是静态分配

邻接表参考dd的dinic代码

Dijkstra1: 我写的的支持内部修改的heap, 

复杂度O((V+E)logV)

Dijkstra2: STL的priority_queue,更新之后结点直接加进堆中而不是更新堆内的结点

复杂度: ???

Dijkstra3: 朴素的Dijkstra

复杂度O(V^2+E)

SPFA:        经典的bellmen-ford的优化,用的最常见的写法,自己写的queue   

复杂度O(k*E), k接近2

USACO:       usaco中butter一题的标程稍作修改,本质与Dijkstra1相似, 

复杂度O((V+E)logV)

 

TEST 1:2000个点的完全图

 

输入输出用时:2.15-2.9秒, 平均:2.47

 

用时(除去平均输入输出时间)

单位:秒:

Dijkstra1: 0.13  0.10

Dijkstra2: 0.05  0.41

Dijkstra3: 0.21  0.18

SPFA:        1.04  0.97

USACO:       0.29  0.40

 

大规模密集图,大量数据的输入输出占用了大部分时间。单纯计算时间太短难以比较。几种dijkstra都有很好的表现,SPFA由于运行时间对于边数的依赖性,显得逊色不少。

对于Dijkstra1和Dijkstra2 因为是密集图,每次找到一个点后无论是内部更新还是重新插入结点,都要O(log n)的复杂度(虽然插入结点的期望复杂度为O(1),但是由于是重新插入结点,堆内同时存在的总结点数可能会达到E的数量级,增大了常数),工作量都是较大的,堆的优势没有体现出来。 相比之下,朴素的Dijkstra的表现相当不错。

 

TEST 2: 100000个结点的链状图

 

输入输出用时:0.10 - 0.30秒, 平均:0.17

 

用时(除去平均输入输出时间)

单位:秒:

Dijkstra1: 0.03  0.07

Dijkstra2: 0.04  0.07

Dijkstra3: >10   >10

SPFA:        0.03  0.00

USACO:       0.15  0.18

 

对于极端的链状图,SPFA无疑是最合适的了。每个结只进队一次,标准的O(E)。朴素的dijkstra对于这样的图就力不从心了:每次循环都过一遍结点,在松弛,然后发现每次O(V)的时间只松弛了一个点。。

Dijkstra2 由于堆内的结点总数最多有E的数量级,稀疏图里和V接近,劣势没有体现出来。

 

 

TEST 3: 20000个结点的稀疏图(每个点100条边)

 

输入输出用时:2.15-2.40 秒, 平均:2.30

 

用时(除去平均输入输出时间)

单位:秒:

Dijkstra1: 0.30  0.33

Dijkstra2: 0.39  0.57

Dijkstra3: 2.20  3.26

SPFA:        5.45  5.11

USACO:       0.27  0.33

 

普通的稀疏图,比TEST 2的密集。 Dijkstra+heap依然是最快的。

比较惊奇的结果是:SPFA居然会比朴素dijkstra还慢……有些出乎预料

原因还没想明白……

 

 

TEST 3: 5000个结点的较密集图(每个点500条边)

 

输入输出用时:2.44-2.99 秒, 平均:2.75

 

用时(除去平均输入输出时间)

单位:秒:

Dijkstra1: 0.30  0.32

Dijkstra2: 0.39  0.33

Dijkstra3: 0.40  0.40

SPFA:        1.04  1.04

USACO:       0.40  0.19

 

比较密集的图。SPFA的表现仍然不佳,Dijkstra+heap 任然是王道,朴素dijkstra的劣势逐渐缩小

 

总结:

 

Dijkstra1对于各种图都有良好表现,但是编程复杂度较高,需要准备模板。Dijkstra2速度也很不错,普遍略逊于Dijkstra1。Dijkstra3对于密集图有不错的表现。

SPFA表现不尽如人意。但是由于SPFA编程复杂度低,适用于各种图,也可以用来负权环,适合比赛使用。

 

编程复杂度:SPFA>naive dijkstra>STLheap+dijkstra>heap+dijkstra(越靠前越容易是写)

综合效率:   heap+dijkstra>STLheap+dijkstra> SPFA>naive dijkstra

比赛的时候 STLheap+dijkstra 和 SPFA 是不错的选择

 

dijkstra1:

 

 

dijkstra2:

 

 

dijkstra3:

 

 

SPFA:

 

USACO:

 

 

以上是关于SPFA和Dijkstra分别适用于什么方面呢?的主要内容,如果未能解决你的问题,请参考以下文章

最短路算法(floyed+Dijkstra+bellman-ford+SPFA)

最短路(Dijkstra,Floyd,Bellman_Ford,SPFA)

算法描述》关于SPFA和Dijkstra算法的两三事

谈一谈Dijkstra

飞行路线 HYSBZ - 2763 (分层图+Dijkstra && Spfa)

最短路总结