一、前提引入

我们学过了Bellman-Ford算法,现在又要提出这个SPFA算法,为什么呢?

考虑一个随机图(点和边随机生成),除了已确定最短路的顶点与尚未确定最短路的顶点之间的边,其它的边所做的都是无用的,大致描述为下图(分割线以左为已确定最短路的顶点):

其中红色部分为所做无用的边,蓝色部分为实际有用的边。既然只需用到中间蓝色部分的边,那就是SPFA算法的优势之处了。

二、算法描述

算法特点:在 Bellman-ford 算法的基础上加上一个队列优化,减少了冗余的松弛操作,是一种高效的最短路算法。

时间复杂度:O(mn)

关键词:初始化    松弛操作    队列

主要变量如下:

int n              表示有n个点,从1~n标号

int s,t            s为源点,t为终点

int dis[N]           dis[i]表示源点s到点i的最短路径

int pre[N]          记录路径,pre[i]表示i的前驱结点

bool vis[N]          vis[i]=true表示点i在队列中

queue<int> q     队列,在整个算法中有顶点入队了要记得标记vis数组,有顶点出队了记得消除那个标记

【初始化】

dis数组全部赋值为INF,pre数组全部赋值为-1(表示还不知道前驱),

dis[s] = 0 表示源点不要求最短路径(或者最短路径就是0)。

【队列+松弛操作】

读取队头顶点u,并将队头顶点u出队(记得消除标记);将与点u相连的所有点v进行松弛操作,如果能更新估计值(即令d[v]变小),那么就更新,另外,如果点v没有在队列中,那么要将点v入队(记得标记),如果已经在队列中了,那么就不用入队,这样不断从队列中取出顶点来进行松弛操作。

以此循环,直到队空为止就完成了单源最短路的求解。

【算法过程】

设立一个队列用来保存待优化的顶点,优化时每次取出队首顶点 u,并且用 u 点当前的最短路径估计值dis[u]对与 u 点邻接的顶点 v 进行松弛操作,如果 v 点的最短路径估计值dis[v]可以更小,且 v 点不在当前的队列中,就将 v 点放入队尾。这样不断从队列中取出顶点来进行松弛操作,直至队列空为止。

【检测负权回路】

方法:如果某个点进入队列的次数大于等于 n,则存在负权回路,其中 n 为图的顶点数。

说明:SPFA无法处理带负环的图。

三、代码实现

  1. #include<iostream>
  2. #include<queue>
  3. #include<stack>
  4. using namespace std;
  5.  
  6. int matrix[100][100]; //邻接矩阵
  7. bool visited[100]; //标记数组
  8. int dist[100]; //源点到顶点i的最短距离
  9. int path[100]; //记录最短路的路径
  10. int enqueue_num[100]; //记录入队次数
  11. int vertex_num; //顶点数
  12. int edge_num; //边数
  13. int source; //源点
  14.  
  15. bool SPFA()
  16. {
  17. memset(visited, 0, sizeof(visited));
  18. memset(enqueue_num, 0, sizeof(enqueue_num));
  19. for (int i = 0; i < vertex_num; i++)
  20. {
  21. dist[i] = INT_MAX;
  22. path[i] = source;
  23. }
  24.  
  25. queue<int> Q;
  26. Q.push(source);
  27. dist[source] = 0;
  28. visited[source] = 1;
  29. enqueue_num[source]++;
  30. while (!Q.empty())
  31. {
  32. int u = Q.front();
  33. Q.pop();
  34. visited[u] = 0;
  35. for (int v = 0; v < vertex_num; v++)
  36. {
  37. if (matrix[u][v] != INT_MAX) //u与v直接邻接
  38. {
  39. if (dist[u] + matrix[u][v] < dist[v])
  40. {
  41. dist[v] = dist[u] + matrix[u][v];
  42. path[v] = u;
  43. if (!visited[v])
  44. {
  45. Q.push(v);
  46. enqueue_num[v]++;
  47. if (enqueue_num[v] >= vertex_num)
  48. return false;
  49. visited[v] = 1;
  50. }
  51. }
  52. }
  53. }
  54. }
  55. return true;
  56. }
  57.  
  58. void Print()
  59. {
  60. for (int i = 0; i < vertex_num; i++)
  61. {
  62. if (i != source)
  63. {
  64. int p = i;
  65. stack<int> s;
  66. cout << "顶点 " << source << " 到顶点 " << p << " 的最短路径是: ";
  67.  
  68. while (source != p) //路径顺序是逆向的,所以先保存到栈
  69. {
  70. s.push(p);
  71. p = path[p];
  72. }
  73.  
  74. cout << source;
  75. while (!s.empty()) //依次从栈中取出的才是正序路径
  76. {
  77. cout << "--" << s.top();
  78. s.pop();
  79. }
  80. cout << " 最短路径长度是:" << dist[i] << endl;
  81. }
  82. }
  83. }
  84.  
  85. int main()
  86. {
  87.  
  88. cout << "请输入图的顶点数,边数,源点:";
  89. cin >> vertex_num >> edge_num >> source;
  90.  
  91. for (int i = 0; i < vertex_num; i++)
  92. for (int j = 0; j < vertex_num; j++)
  93. matrix[i][j] = INT_MAX; //初始化matrix数组
  94.  
  95. cout << "请输入" << edge_num << "条边的信息:\n";
  96. int u, v, w;
  97. for (int i = 0; i < edge_num; i++)
  98. {
  99. cin >> u >> v >> w;
  100. matrix[u][v] = w;
  101. }
  102.  
  103. if (SPFA())
  104. Print();
  105. else
  106. cout << "Sorry,it have negative circle!\n";
  107.  
  108. return 0;
  109. }

运行如下:

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

  1. 最短路径--SPFA 算法

    适用范围:给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了. 我们约定有向加权图G不存在负权回路,即最短路径一 ...

  2. 图的最短路径-----------SPFA算法详解(TjuOj2831_Wormholes)

    这次整理了一下SPFA算法,首先相比Dijkstra算法,SPFA可以处理带有负权变的图.(个人认为原因是SPFA在进行松弛操作时可以对某一条边重复进行松弛,如果存在负权边,在多次松弛某边时可以更新该 ...

  3. 最短路径----SPFA算法

    求最短路径的算法有许多种,除了排序外,恐怕是ACM界中解决同一类问题算法最多的了.最熟悉的无疑是Dijkstra,接着是Bellman-Ford,它们都可以求出由一个源点向其他各点的最短路径:如果我们 ...

  4. 最短路径SPFA算法(邻接表存法)

    queue <int> Q; void SPFA (int s) { int i, v; for(int i=0; i<=n; i++) dist[i]=INF; //初始化每点i到 ...

  5. 洛谷P3371单源最短路径SPFA算法

    SPFA同样是一种基于贪心的算法,看过之前一篇blog的读者应该可以发现,SPFA和堆优化版的Dijkstra如此的相似,没错,但SPFA有一优点是Dijkstra没有的,就是它可以处理负边的情况. ...

  6. 最短路径问题的Dijkstra和SPFA算法总结

    Dijkstra算法: 解决带非负权重图的单元最短路径问题.时间复杂度为O(V*V+E) 算法精髓:维持一组节点集合S,从源节点到该集合中的点的最短路径已被找到,算法重复从剩余的节点集V-S中选择最短 ...

  7. Bellman-Ford & SPFA 算法——求解单源点最短路径问题

    Bellman-Ford算法与另一个非常著名的Dijkstra算法一样,用于求解单源点最短路径问题.Bellman-ford算法除了可求解边权均非负的问题外,还可以解决存在负权边的问题(意义是什么,好 ...

  8. 最短路径算法之四——SPFA算法

    SPAF算法 求单源最短路的SPFA算法的全称是:Shortest Path Faster Algorithm,该算法是西南交通大学段凡丁于1994年发表的. 它可以在O(kE)的时间复杂度内求出源点 ...

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

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

随机推荐

  1. Android在代码中设置控件的drawableLeft,drawableRight,drawableTop,drawableBottom。

    根据业务的需要,要在代码中设置控件的drawableLeft,drawableRight,drawableTop,drawableBottom属性. 我们知道在xml中设置的方法为:android:d ...

  2. 推荐几本对于Python初学者比较好的书籍(内含PDF)

    我们提供一个初学者最好的Python书籍列表.Python是一个初级程序员可以学习编程的最友好语言之一.为了帮助您开始使用Python编程,我们分享此列表.泡一杯茶,选一本书阅读,开始使用Python ...

  3. How to Enable TLS 1.2 on Windows Server 2008 R2 and IIS 7.5

    Nowadays there is an SSL vulnerability called POODLE discovered by Google team in SSLv3 protocol. So ...

  4. Luogu P3177 [HAOI2015]树上染色

    一道有机结合了计数和贪心这一DP两大考点的神仙题,不得不说做法是很玄妙. 首先我们很容易想到DP,设\(f_{i,j}\)表示在以\(i\)为根节点的子树中选\(j\)个黑色节点的最大收益值. 然后我 ...

  5. Luogu P2597 [ZJOI2012]灾难

    一道非常综合的好题然后就莫名其妙地知道了动态LCA的求法 果然是ZJOI的题目,只能说这思路服了 首先我们发现每次操作只会灭绝一种动物,然后我们想一下就知道如果有\(n(n>=2)\)个食物的动 ...

  6. 【Java并发.1】简介

    继上一本<深入理解Java虚拟机>之后,学习计划里的另一本书<Java并发编程实战>现在开始学习,并记录学习笔记. 第一章主要内容是介绍 并发 的简介.发展.特点. 编写正确的 ...

  7. [UWP 自定义控件]了解模板化控件(3):实现HeaderedContentControl

    1. 概述 来看看这段XMAL: <StackPanel Width="300"> <TextBox Header="TextBox" /&g ...

  8. python爬虫xpath的语法

    有朋友问我正则,,okey,其实我的正则也不好,但是python下xpath是相对较简单的 简单了解一下xpath: XPath 是一门在 XML 文档中查找信息的语言.XPath 可用来在 XML ...

  9. TRIO-basic指令--FLEXLINK

    Type: Axis Command Syntax: FLEXLINK(base_dist, excite_dist, link_dist, base_in, base_out, excite_acc ...

  10. Windows10 家庭版 Docker的安装

    Docker的安装 1.简介:Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中, 然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全 ...