SPFA(Shortest Path Faster Algorithm)学习手记

昨天刚刚学习了西南交大段凡丁教授提出的Bellman-ford改进版---SPFA算法。从名字就可以看出该算法应该很快。从昨天做的一道题:n=100W,E=8*N的图,跑SPFA只花了700MS,可以证实该算法效率确实很高。

 

当初学算法导论上的Bellman-ford的时候就觉得这个算法有点暴力,做了很多冗余计算。举例来看,有图为:v0->v1->v2->v3(每边权值为1),Bellman-ford要做3次循环,假定每次循环按(v2,v3),(v1,v2),(v0,v1)的顺序松弛,实际效果是每次循环只改变了一个点的估计,算法总共要做9次松弛。而事实上,从v0出发,只要松弛3次就可以完成这个任务。

 

上述算法冗余的地方在于:用了未被优化的点来松弛别的边。比如前两次循环中,d[v2]均为inf,那么用v2来松弛别的边是毫无意义的。

 

而段教授的SPFA的优点在于,每次只用被优化过的点来松弛别的边。

算法框架如下:

SPFA(G,w,s)

  1. INITIALIZE-SINGLE-SOURCE(G,s)

  2. INITIALIZE-QUEUE(Q)

  3. ENQUEUE(Q,s)

  4. While Not EMPTY(Q)

  5. Do u<-DLQUEUE(Q)

  6. For 每条边(u,v) in E[G]

  7. Do tmp<-d[v]

  8. Relax(u,v,w)

  9. If (d[v] < tmp) and (v不在Q中)    //这一步保证了用来松弛别的边的点都是被优化过的!

  10. ENQUEUE(Q,v)

 

算法正确性的证明可以用到路径松弛性质(详见算法导论P361):

如果p=< v0,v1,…,vk > 是从s=v0 到 vk 的最短路径, 而且p的边按照(v0,v1)(v1,v2),…,(v(k-1),vk) 的顺序进行松弛,那么k[vk] = dis(s,vk)。这个性质的保持并不受其他松弛操作的影响,即使它们与p的边上的松弛操作混合在一起也是一样的。

假定没有负权环。

 

证明如下:

设p为v0->vk的最短路径中节点数最少的一条,设按顺序松弛到(vi-1,vi),那么vi必在队列中,否则与"最短路径"或"节点数最少"矛盾,所以接下来松弛的边为(vi,vi+1)。这样循环不变式在初始条件成立,并一直维持到算法结束。证毕。

 

如果某个节点入队次数大于N,必定存在负权环。这点小弟不会证明,望路过的大牛不吝赐教。

 

SPFA算法的复杂度为O(kE),k为平均入队次数。段教授的论文中说明,经过大量的实验,k在通常情况下都在2以下。

相比较Bellman-ford的O(VE)是个巨大的改进。

而dijkstra用二叉堆实现复杂度为(ElogV),用斐波那契堆为(VlogV),因此dijkstra可能在边多的情况下理论上更快一点。但考虑到编程的复杂性,具有O(E)复杂度的SPFA是个相当优异的算法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值