`
v_JULY_v
  • 浏览: 69324 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

十三、通过浙大上机复试试题学SPFA 算法

阅读更多

十三、通过浙大上机复试试题学SPFA 算法

作者:July、sunbaigui。二零一一年三月二十五日。
出处:http://blog.csdn.net/v_JULY_v
------------------


前言:
本人不喜欢写诸如“如何学算法”此类的文章,一来怕被人认为是自以为是,二来话题太泛,怕扯得太远,反而不着边际。所以,一直不打算写怎么学习算法此类的文章。

不过,鉴于读者的热心支持与关注,给出以下几点小小的建议,仅供参考:
1、算法,浩如烟海,找到自己感兴趣的那个分支,或那个点来学习,然后,一往无前的深入探究下去。
2、兴趣第一,忌浮躁。
3、思维敏捷。给你一道常见的题目,你的头脑中应该立刻能冒出解决这道问题的最适用的数据结构,以及算法。
4、随兴趣,多刷题。不一定要刷什么ACM题。一切,由着你的兴趣走,poj,面试题,包括下文将出现的研究生复试上机考试题,都可以作为你的编程练习题库。
5、多实践,多思考。学任何一个算法,反复研究,反复思考,反复实现。
6、数据结构是一切的基石。不必太过专注于算法,一切算法的实现,原理都是依托数据结构来实现的。弄懂了一个数据结构,你也就通了一大片算法。
7、学算法,重优化。优化的道理,相信大家都懂,不用我多说什么。
8、以后想到后,补充。

ok,话不再多。希望,对你有用。
接下来,咱们来通过最近几年的浙大研究生复试上机试题,来学习或巩固常用的算法。


浙大研究生复试2010年上机试题-最短路径问题
问题描述:
给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。

输入:输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点t。n和m为0时输入结束。
(1<n<=1000, 0<m<100000, s != t)
输出:一行有两个数, 最短距离及其花费。(下文,会详细解决)


几个最短路径算法的比较
ok,怎么解决上述的最短路径问题列?提到最短路径问题,想必大家会立马想到Dijkstra 算法,但Dijkstra 算法的效率如何列?
我们知道,Dijkstra 算法的运行时间,依赖于其最小优先队列的采取何种具体实现决定,而最小优先队列可有以下三种实现方法:
1、利用从1至|V| 编好号的顶点,简单地将每一个d[v]存入一个数组中对应的第v项,
如上述DIJKSTRA(G,w,s)所示,Dijkstra 算法的运行时间为O(V^2+E)。
2、如果是二叉/项堆实现最小优先队列的话,EXTRACT-MIN(Q)的运行时间为O(V*lgV),
所以,Dijkstra 算法的运行时间为O(V*lgV+E*lgV),
若所有顶点都是从源点可达的话,O((V+E)*lgV)=O(E*lgV)。
当是稀疏图时,则E=O(V^2/lgV),此Dijkstra 算法的运行时间为O(V^2)。
3、采用斐波那契堆实现最小优先队列的话,EXTRACT-MIN(Q)的运行时间为O(V*lgV),
所以,此Dijkstra 算法的运行时间即为O(V*lgV+E)。

综上所述,此最小优先队列的三种实现方法比较如下:

EXTRACT-MIN + RELAX
I、 简单方式: O(V*V + E*1)
II、 二叉/项堆: O(V*lgV + |E|*lgV)
源点可达:O(E*lgV)
稀疏图时,有E=o(V^2/lgV),
=> O(V^2)
III、斐波那契堆:O(V*lgV + E)

是的,由上,我们已经看出来了,Dijkstra 算法最快的实现是,采用斐波那契堆作最小优先队列,算法时间复杂度,可达到O(V*lgV + E)。

但是列?如果题目有时间上的限制列?vlgv+e的时间复杂度,能否一定满足要求?我们试图寻找一种解决此最短路径问题更快的算法。

这个时候,我们想到了Bellman-Ford算法:求单源最短路,可以判断有无负权回路(若有,则不存在最短路),时效性较好,时间复杂度O(VE)。不仅时效性好于上述的Dijkstra 算法,还能判断回路中是否有无负权回路。

既然,想到了Bellman-Ford算法,那么时间上,是否还能做进一步的突破。对了,我们中国人自己的算法--SPFA算法:SPFA算法,Bellman-Ford的队列优化,时效性相对好,时间复杂度O(kE)。(k<<V)。
是的,线性的时间复杂度,我想,再苛刻的题目,或多或少,也能满足要求了。


什么是SPFA算法
在上一篇文章二之三续、Dijkstra 算法+Heap堆的完整c实现源码中,我们给出了Dijkstra+Heap堆的实现。其实,在稀疏图中对单源问题来说SPFA的效率略高于 Heap+Dijkstra ;对于无向图上的APSP(All Pairs Shortest Paths)问题,SPFA算法加上优化后效率更是远高于Heap+Dijkstra。

那么,究竟什么是SPFA算法列?

SPFA算法,Shortest Path Faster Algorithm,是由西南交通大学段凡丁于1994年发表的。正如上述所说,Dijkstra 算法无法用于负权回路,很多时候,如果给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了。
  
简洁起见,我们约定有向加权图G不存在负权回路,即最短路径一定存在。当然,我们可以在执行该算法前做一次拓扑排序,以判断是否存在负权回路。

我们用数组d记录每个结点的最短路径估计值,而且用邻接表来存储图G。
我们采取的方法是动态逼近法:设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。
这样不断从队列中取出结点来进行松弛操作,直至队列空为止。

定理: 只要最短路径存在,上述SPFA算法必定能求出最小值。
期望的时间复杂度O(ke), 其中k为所有顶点进队的平均次数,可以证明k一般小于等于2。

SPFA实际上是Bellman-Ford基础上的优化,以下,是此算法的伪代码:

//这里的q数组表示的是节点是否在队列中,如q[v]=1则点v在队列中 
SPFA(G,w,s)    
1. INITIALIZE-SINGLE-SOURCE(G,s)   
2. Q ← &Oslash;   
3. for each vertex ∈ V[G]   
4. q[v]=0   
5. ENQUEUE(Q,s)   
6. q[s]=1   
7. while Q≠&Oslash;   
8. do u ← DEQUEUE(Q)   
9. q[u]=0   
10.for each edge(u,v) ∈ E[G]   
11. do t ← d[v]   
12. RELAX(u,v,w)   
13. π[v] ← u   
14. if (d[v] < t)   
15. ENQUEUE(Q,v)   
16. q[v]=1

SPFA是Bellman-Ford的队列优化,时效性相对好,时间复杂度O(kE)。(k<<V)。
与Bellman-ford算法类似,SPFA算法采用一系列的松弛操作以得到从某一个节点出发到达图中其它所有节点的最短路径。所不同的是,SPFA算法通过维护一个队列,使得一个节点的当前最短路径被更新之后没有必要立刻去更新其他的节点,从而大大减少了重复的操作次数。

与Dijkstra算法与Bellman-ford算法不同,SPFA的算法时间效率是不稳定的,即它对于不同的图所需要的时间有很大的差别。在最好情形下,每一个节点都只入队一次,则算法实际上变为广度优先遍历,其时间复杂度仅为O(E)。另一方面,存在这样的例子,使得每一个节点都被入队(V-1)次,此时算法退化为Bellman-ford算法,其时间复杂度为O(VE)。有研究指出在随机情形下平均一个节点入队的次数不超过2次,因此算法平均的时间复杂度为O(E),甚至优于使用堆优化过的Dijkstra算法。


最短路径问题的解决
浙大研究生复试2010年上机试题-最短路径问题
问题描述:
给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。

输入:输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点t。n和m为0时输入结束。
(1<n<=1000, 0<m<100000, s != t)
输出:一行有两个数, 最短距离及其花费。

接下来,咱们便利用SPFA 算法来解决此最短路径问题。
以下,便引用sunbaigui的代码来说明此问题:
声明几个变量:
建个数据结构:

以下是关键代码 主函数测试用例:
运行结果,是:

最后,总结一下(Lunatic Princess):
(1)对于稀疏图,当然是SPFA的天下,不论是单源问题还是APSP问题,SPFA的效率都是最高的,写起来也比Dijkstra简单。对于无向图的APSP问题还可以加入优化使效率提高2倍以上。
(2)对于稠密图,就得分情况讨论了。单源问题明显还是Dijkstra的势力范围,效率比SPFA要高2-3倍。APSP问题,如果对时间要求不是那么严苛的话简简单单的Floyd即可满足要求,又快又不容易写错;否则就得使用Dijkstra或其他更高级的算法了。如果是无向图,则可以把Dijkstra扔掉了,加上优化的SPFA绝对是必然的选择。

稠密图 稀疏图有负权边
----------------------------------------------------------------------------------------------
单源问题 Dijkstra+heap SPFA(或Dijkstra+heap,根据稀疏程度) SPFA
APSP(无向图) SPFA(优化)/Floyd SPFA(优化) SPFA(优化)
APSP(有向图) Floyd SPFA (或Dijkstra+heap,根据稀疏程度)SPFA

完。

版权所有。转载本BLOG内任何文章,请以超链接形式注明出处。
否则,一经发现,必定永久谴责+追究法律责任。谢谢,各位。

分享到:
评论

相关推荐

    十三个常用算法

    一、A*搜索算法 一(续)、A*,Dijkstra,BFS 算法性能比较及A*算法的应用 二、Dijkstra 算法初探 二(续)、彻底理解Dijkstra 算法 二(再续)、Dijkstra 算法+fibonacci 堆...十三、通过浙大上机复试试题学SPFA 算法

    SPFA算法优化及应用

    SPFA算法的基本思想是通过relax操作来更新节点的距离值。relax操作的定义为: Relax(u,v){If F(v)&gt;F(u)+W_Cost(u,v) then F(v)=F(u)+W_Cost(u,v);} 其中,F(u)和F(v)分别表示节点u和v的距离值,W_Cost(u,v)表示边...

    Dijkstra与SPFA算法的不同之处对比

    SPFA算法 此处为SPFA算法详解 用dis数组记录源点到有向图上任意一点距离,其中源点到自身距离为0,到其他点距离为 INF。将源点入队,并重复以下步骤: 1、队首x出队 2、遍历所有以队首为起点的有向边(x,i),若...

    SPFA算法的优化及应用

    ### SPFA算法的优化及应用 #### SPFA算法概述与基本原理 SPFA(Shortest Path Faster Algorithm)算法是基于Bellman-Ford算法的一种改进版本,主要针对带权有向图中的最短路径问题。该算法的核心思想在于利用队列...

    最短路径 之 SPFA算法

    SPFA最短路径算法 SPFA(Shortest Path Faster Algorithm)是一种单源最短路径算法,它的性能非常好,代码实现也并不复杂。特别是当图的规模大,用邻接矩阵存不下的时候,用 SPFA 则可以很方便地面对临接表。每个...

    SPFA算法.doc

    SPFA(Shortest Path Faster Algorithm)算法是一种用于解决图论中的单源最短路径问题的算法,它是贝尔曼-福特(Bellman-Ford)算法的一种优化版本,主要应用于求解带有负权重边的图的最短路径。SPFA通过使用队列...

    spfa算法的java实现

    SPFA(Shortest Path Faster Algorithm)算法是一种求解图中单源最短路径问题的算法,它是Bellman-Ford算法的一种优化版本。在Java中实现SPFA算法,我们需要理解其核心思想并熟悉Java编程语法。 SPFA算法的主要优点...

    国家集训队2009论文集SPFA算法的优化及应用

    SPFA(Shortest Path Faster Algorithm)算法是一种求解图中单源最短路径问题的算法,由美国卡耐基梅隆大学的姚新教授提出。它在Bellman-Ford算法的基础上进行了一些优化,使得在某些情况下能更快地找到最短路径。本...

    SPFA算法模板

    ### SPFA算法详解 #### 一、算法简介 SPFA(Shortest Path Faster Algorithm)算法是一种高效的单源最短路径算法。它由西南交通大学的段凡丁教授在1994年提出。与传统的最短路径算法如Dijkstra算法相比,SPFA在...

    java spfa 算法 demo 最短路径双向

    现在网上有很多最短路径的算法,C++版本的较多,java可用的demo较少,或者不支持双向的,这里总结了java版的spfa算法,个人认为此算法比较实用(拓扑、GIS定位等项目上),本算法支持双向,有兴趣的可以下载下来研究...

    SPFA算法求单源最短路径

    **SPFA(Shortest Path Faster Algorithm)算法是求解图中单源最短路径的一种算法,它是Bellman-Ford算法的一种优化版本。该算法由Liu Hui在1990年提出,主要应用于图论和网络流问题中。与Dijkstra算法不同,SPFA...

    SPFA算法.zip

    SPFA算法就解决了重复计算的问题,在大数据面前大大减少运行时间 该算法改善的思想是避免顶点进行无效的重复更新,对有待更新的顶点移入队列,已更新的顶点移出队列,避免待更新的顶点中存在重复顶点

    SPFA算法.ppt

    “三角形两边之和大于第三边” 在信息学中我们叫它三角不等式。 所谓对i,j进行松弛,就是判定是否d[j]&gt;d[i]+w[i,j],如果该式成立则将d[j]减小到d[i]+w[i,j],否则不动。 d[i]:起点s到i的临时最短路长度 松驰的...

    c++ SPFA算法

    C++ SPFA算法 SPFA(Shortest Path Faster Algorithm)是一种求解单源最短路径问题的算法,它可以在O(kE)的时间复杂度内求出源点到其他所有点的最短路径,并且可以处理负边。该算法的基本思想是使用一个队列来维护...

    SPFA.zip_SPFA_oppositejx4_originalyu7_spfa算法_图论

    **SPFA算法详解** SPFA(Shortest Path Faster Algorithm,最短路径更快算法)是一种用于解决图论中的单源最短路径问题的算法,由姚紫金在2000年提出。它与Dijkstra算法相比,对于某些图类型,如负权边的图,SPFA...

    SPFA算法 算法简介 简介.docx

    SPFA(Shortest Path Faster Algorithm)算法是一种用于解决图论中的单源最短路径问题的算法,它是Bellman-Ford算法的一种优化实现,主要目的是减少不必要的冗余计算。SPFA算法在存在负权边的图中特别有用,因为它...

    求单源点最短路径效率很高的spfa算法

    **SPFA算法详解** SPFA(Shortest Path Faster Algorithm)是一种用于解决图论中的单源最短路径问题的算法,由姚一兆提出。相比于Dijkstra算法,SPFA在处理某些稠密图时表现出更高的效率,尽管它不是一种确定性的...

    SPFA.cpp SPFA算法

    最短路SPFA算法。SPFA(Shortest Path Faster Algorithm)算法是求单源最短路径的一种算法,它是Bellman-ford的队列优化,它是一种十分高效的最短路算法。存在负权边时使用。

Global site tag (gtag.js) - Google Analytics