SPAF算法

求单源最短路的SPFA算法的全称是:Shortest Path Faster Algorithm,该算法是西南交通大学段凡丁于1994年发表的。

它可以在O(kE)的时间复杂度内求出源点到其他所有点的最短路径。

其中k为所有顶点进队的平均次数,可以证明k一般小于等于2,可以处理负边,但无法处理带负环的图(负环和负边不是一个概念)。

SPFA的实现甚至比Dijkstra或者Bellman_Ford还要简单。

SPFA算法过程:
  我们记源点为S,由源点到达点i的“当前最短路径”为D[i],开始时将所有D[i]初始化为无穷大,D[S]则初始化为0。算法所要做的,就是在运行过程中,不断尝试减小D[]数组的元素,最终将其中  每一个元素减小到实际的最短路径。
  过程中,我们要维护一个队列,开始时将源点置于队首,然后反复进行这样的操作,直到队列为空:
  (1)从队首取出一个结点u,扫描所有由u结点可以一步到达的结点,具体的扫描过程,随存储方式的不同而不同;
  (2)一旦发现有这样一个结点,记为v,满足D[v] > D[u] + w(u, v),则将D[v]的值减小,减小到和D[u] + w(u, v)相等。其中,w(u, v)为图中的边u-v的长度,由于u-v必相邻,所以这个长度一定已知(不然我们得到的也不叫一个完整的图);这种操作叫做松弛。
  (3)上一步中,我们认为我们“改进了”结点v的最短路径,结点v的当前路径长度D[v]相比于以前减小了一些,于是,与v相连的一些结点的路径长度可能会相应地减小。注意,是可能,而不是一定。但即使如此,我们仍然要将v加入到队列中等待处理,以保证这些结点的路径值在算法结束时被降至最优。

判断有无负环:
  如果某个点进入队列的次数超过N次则存在负环(SPFA无法处理带负环的图)
  对于不存在负权回路的图来说,上述算法是一定会结束的。因为算法在反复优化各个最短路径长度,总有一个时刻会进入“无法再优化”的局面,此时一旦队列读空,算法就结束了。然而,如果图中存  在一条权值为负的回路,就糟糕了,算法会在其上反复运行(因为d[]加上一个负数肯定变下了,所以在有负环的情况下,会不断有数进入队列),通过“绕圈”来无休止地试图减小某些相关点的最短路  径值。假如我们不能保证图中没有负权回路,一种“结束条件”是必要的。这种结束条件是什么呢?
  思考Bellman-Ford算法,它是如何结束的?显然,最朴素的Bellman-Ford算法不管循环过程中发生了什么,一概要循环|V|-1遍才肯结束。凭直觉我们可以感到,SPFA算法“更聪明一些”,就是说我  们可以猜测,假如在SPFA中,一个点进入队列——或者说一个点被处理——超过了|V|次,那么就可以断定图中存在负权回路了。

SPFA代码实现(以HDU1535为例):

  1. #include<stdio.h>
  2. #include<limits.h>
  3. #include<iostream>
  4. #include<string>
  5. #include<queue>
  6. #define MAXN 1000000
  7. using namespace std;
  8. struct e
  9. {
  10. int begin;
  11. int end;
  12. int dis;
  13. } edge1[MAXN+],edge2[MAXN+];
  14. int dis[MAXN+],first[MAXN+];
  15. bool vis[MAXN+];
  16. int T,S,D,N,k,M;
  17. void SPFA(int begin,struct e edge[])
  18. {
  19. for (int i=; i<=N; i++)
  20. {
  21. dis[i]=INT_MAX;
  22. vis[i]=;
  23. }
  24. queue <int> Q;
  25. Q.push(begin);
  26. dis[begin]=;
  27. while (!Q.empty())
  28. {
  29. begin=Q.front();
  30. Q.pop();
  31. vis[begin]=;
  32. for (int i=first[begin]; edge[i].begin==begin; i++)
  33. if (dis[edge[i].end]>dis[begin]+edge[i].dis)
  34. {
  35. dis[edge[i].end]=dis[begin]+edge[i].dis;
  36. if (!vis[edge[i].end])
  37. {
  38. Q.push(edge[i].end);
  39. vis[edge[i].end]=;
  40. }
  41. }
  42. }
  43. }
  44. void init(struct e edge[])
  45. {
  46. memset(first,,sizeof(first));
  47. first[edge[].begin]=;
  48. for (int i=; i<=M; i++)
  49. if (edge[i-].begin!=edge[i].begin) first[edge[i].begin]=i;
  50. }
  51. bool cmp(struct e a,struct e b)
  52. {
  53. return a.begin<b.begin;
  54. }
  55. int main()
  56. {
  57. int T;
  58. cin>>T;
  59. while (T--)
  60. {
  61. scanf("%d %d",&N,&M);
  62. int x1,x2,x3;
  63. for (int i=; i<=M; i++)
  64. {
  65. scanf("%d %d %d",&x1,&x2,&x3);
  66. edge1[i].begin=x1,edge1[i].end=x2,edge1[i].dis=x3;
  67. edge2[i].begin=x2,edge2[i].end=x1,edge2[i].dis=x3;
  68. }
  69. sort(edge1+,edge1+M+,cmp);
  70. sort(edge2+,edge2+M+,cmp);
  71. init(edge1);
  72. SPFA(,edge1);
  73. int cnt=;
  74. for (int i=; i<=N; i++)
  75. cnt+=dis[i];
  76. init(edge2);
  77. SPFA(,edge2);
  78. for (int i=; i<=N; i++)
  79. cnt+=dis[i];
  80. printf("%d\n",cnt);
  81. }
  82. return ;
  83. }

  期望的时间复杂度:O(ke), 其中k为所有顶点进队的平均次数,可以证明k一般小于等于2。

最短路径算法之四——SPFA算法的更多相关文章

  1. 数据结构与算法--最短路径之Bellman算法、SPFA算法

    数据结构与算法--最短路径之Bellman算法.SPFA算法 除了Floyd算法,另外一个使用广泛且可以处理负权边的是Bellman-Ford算法. Bellman-Ford算法 假设某个图有V个顶点 ...

  2. 最短路径——Bellman-Ford算法以及SPFA算法

    说完dijkstra算法,有提到过朴素dij算法无法处理负权边的情况,这里就需要用到Bellman-Ford算法,抛弃贪心的想法,牺牲时间的基础上,换取负权有向图的处理正确. 单源最短路径 Bellm ...

  3. Bellman-Ford算法与SPFA算法详解

    PS:如果您只需要Bellman-Ford/SPFA/判负环模板,请到相应的模板部分 上一篇中简单讲解了用于多源最短路的Floyd算法.本篇要介绍的则是用与单源最短路的Bellman-Ford算法和它 ...

  4. Bellman-ford算法、SPFA算法求解最短路模板

    Bellman-ford 算法适用于含有负权边的最短路求解,复杂度是O( VE ),其原理是依次对每条边进行松弛操作,重复这个操作E-1次后则一定得到最短路,如果还能继续松弛,则有负环.这是因为最长的 ...

  5. 图论-最短路径--3、SPFA算法O(kE)

    SPFA算法O(kE) 主要思想是:     初始时将起点加入队列.每次从队列中取出一个元素,并对所有与它相邻的点进行修改,若某个相邻的点修改成功,则将其入队.直到队列为空时算法结束.     这个算 ...

  6. 题目1008:最短路径问题(SPFA算法)

    问题来源 http://ac.jobdu.com/problem.php?pid=1008 问题描述 给定一个G(V,E)有向图,起点s以及终点t,求最短路径. 问题分析 典型的单源最短路径问题,可以 ...

  7. 最短路径算法 4.SPFA算法(1)

    今天所说的就是常用的解决最短路径问题最后一个算法,这个算法同样是求连通图中单源点到其他结点的最短路径,功能和Bellman-Ford算法大致相同,可以求有负权的边的图,但不能出现负回路.但是SPFA算 ...

  8. 最短路径问题---Floyed(弗洛伊德算法),dijkstra算法,SPFA算法

    在NOIP比赛中,如果出图论题最短路径应该是个常考点. 求解最短路径常用的算法有:Floyed算法(O(n^3)的暴力算法,在比赛中大概能过三十分) dijkstra算法 (堆优化之后是O(MlogE ...

  9. [hihoCoder] #1093 : 最短路径·三:SPFA算法

    时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 万圣节的晚上,小Hi和小Ho在吃过晚饭之后,来到了一个巨大的鬼屋! 鬼屋中一共有N个地点,分别编号为1..N,这N个地点之 ...

随机推荐

  1. 代码实现IMapcontrol当前视图输出为图片功能

    SaveFileDialog dialog = new SaveFileDialog(); dialog.Title = "保存输出图片"; dialog.Filter = &qu ...

  2. ZigBee 入网详解

    本文将根据Sniffer来详细解释ZigBee终端设备入网的整个流程,原创博文. 当协调器建立好网络后,终端设备执行zb_startrequest函数,准备入网时,他们两者之间详细的流程如下.

  3. 关联 Android 源代码 到 Ecplise

    1. 下载android 源码存于本地硬盘; 2. 打开Eclpise, 新建Android Project; 3. 在MainActivity文件中,按住Ctrl 点击Activity类 4. 弹出 ...

  4. RadioStream应用源码完整版(iphone版和ipad版)

    RadioStream应用源码完整版(iphone版和ipad版),这个项目是从那个ios教程网分析过了的,也是一个不错的国外音乐应用的,支持iphone版和ipad版. <ignore_js_ ...

  5. javascript之高级函数应用思想

    1.级联函数:应用对象方法调用的连写 function A(){ this.a = ''; this.b = ''; this.c = ''; } //改造一下 A.prototype = { A.p ...

  6. ASP.NET Web API标准的“管道式”设计

    详见:http://www.cnblogs.com/artech/p/asp-net-web-api-pipeline.html http://www.codeproject.com/Articles ...

  7. js鼠标及对象坐标控制属性详细解析

    对js鼠标及对象坐标控制属性进行了详细的分析介绍.  offsetTop获取对象相对于版面或由 offsetParent 属性指定的父坐标的计算顶端位置. offsetLeft获取对象相对于版面或由 ...

  8. 删除_desktop.ini病毒文件

    del h:\_desktop.ini /f/s/q/a/f 强制删除只读文件/s 从当前目录及其所有子目录栓出指定文件.显示正在删除的文件名/q 制定清音状态.不提示确认删除/a 按照属性来删除

  9. 【ibatis】cachemodel、属性 及特殊配置

    http://www.cnblogs.com/13590/archive/2013/03/01/2938126.html <?xml version="1.0" encodi ...

  10. 【BZOJ 1040】 [ZJOI2008]骑士

    Description Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战火 ...