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+10],edge2[MAXN+10];
14 int dis[MAXN+10],first[MAXN+10];
15 bool vis[MAXN+10];
16 int T,S,D,N,k,M;
17 void SPFA(int begin,struct e edge[])
18 {
19     for (int i=1; i<=N; i++)
20     {
21         dis[i]=INT_MAX;
22         vis[i]=0;
23     }
24     queue <int> Q;
25     Q.push(begin);
26     dis[begin]=0;
27     while (!Q.empty())
28     {
29         begin=Q.front();
30         Q.pop();
31         vis[begin]=0;
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]=1;
40                 }
41             }
42     }
43 }
44 void init(struct e edge[])
45 {
46     memset(first,0,sizeof(first));
47     first[edge[1].begin]=1;
48     for (int i=2; i<=M; i++)
49         if (edge[i-1].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=1; 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+1,edge1+M+1,cmp);
70         sort(edge2+1,edge2+M+1,cmp);
71         init(edge1);
72         SPFA(1,edge1);
73         int cnt=0;
74         for (int i=1; i<=N; i++)
75             cnt+=dis[i];
76         init(edge2);
77         SPFA(1,edge2);
78         for (int i=1; i<=N; i++)
79             cnt+=dis[i];
80         printf("%d\n",cnt);
81     }
82     return 0;
83 }

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

转载于:https://www.cnblogs.com/Enumz/p/3862690.html

最短路径算法之四——SPFA算法相关推荐

  1. #1093 : 最短路径·三:SPFA算法(邻接表)

    #1093 : 最短路径·三:SPFA算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 万圣节的晚上,小Hi和小Ho在吃过晚饭之后,来到了一个巨大的鬼屋! 鬼屋中一共 ...

  2. 【最短路径】:Dijkstra算法、SPFA算法、Bellman-Ford算法和Floyd-Warshall算法

    求最短路径最常用的算法有: Dijkstra算法.SPFA算法.Bellman-Ford算法和Floyd-Warshall算法. Dijkstra算法.SPFA算法.Bellman-Ford算法这三个 ...

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

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

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

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

  5. 最短路径问题(Floyd算法、Dijkstra算法、Bellman-Ford算法、SPFA算法)

    导入 最短路径问题是指在一幅带权图中,找出连接两个顶点之间的所有路径中,边权和最短的那一条.如下图就是一幅带权图,边上的数字就代表该边的权值.解决最短路径问题有多种不同的算法,本文将对它们的基本思想与 ...

  6. 单源最短路 Dijkstra算法 和 SPFA算法

    单源最短路 •从一个点出发,到达其他顶点的最短路径的长度. •基本操作:松弛 •d[u]+map[u, v]< d[v]这样的边(u,v)称为紧的(tense),可以对它进行松弛(relax): ...

  7. floyed算法、dijkstra算法、SPFA算法

    转自gzr的博客:https://www.cnblogs.com/TFLS-gzr/p/10381849.html,https://www.cnblogs.com/TFLS-gzr/p/1038746 ...

  8. I won't tell you this is about graph theory----zjfc bellman-ford算法与spfa算法

    题目描述 To think of a beautiful problem description is so hard for me that let's just drop them off. :) ...

  9. BellmanFord算法与SPFA算法

    Bellman-Ford Bellman-Ford 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法.该算法由 Richard Be ...

  10. 常用代码模板3——搜索与图论(Bellman-Ford算法 、spfa 算法、floyd算法、Kruskal算法、染色法、匈牙利算法 )

    目录 一.树与图的存储 二.树与图的遍历 (1) 深度优先遍历 -- 模板题 AcWing 846. 树的重心 (2) 宽度优先遍历 -- 模板题 AcWing 847. 图中点的层次 拓扑排序 -- ...

最新文章

  1. 5-flutter 布局和列表
  2. 先本地仓库中国添加jar包
  3. 机器学习笔记:GRU
  4. 给你汇报Struts2 S2-016漏洞修复的总结
  5. proxy error: could not proxy request解决方案
  6. 【Linux】一步一步学Linux——passwd文件详解(107)
  7. 【招聘(深圳)】轻岁 诚聘.NET Core开发
  8. 实现两数 交换的三种不同编程方法。
  9. intellisense_SQL Server IntelliSense的使用和故障排除–适用于SQL Server 2012或更高版本
  10. 查询同一张表符合条件的某些数据的id拼接成一个字段返回
  11. 505_TextWatcher可以重复添加
  12. 山西大学量子计算机,关于量子力学与量子计算机
  13. 中国 各大银行bankCode 开户行代码和名称 高清银行图标
  14. 程序员笔试题收集汇总(三)
  15. 一个成功的BI项目实施需要注意哪些? 1
  16. This probably means that Tcl wasn‘t installed properly报错
  17. python如何解析网页的json_python 如何从网页jQuery中爬取JSON中的内容
  18. 2019 掘安杯 JACTF MISC WP
  19. 大二上半学期还挂科两门,大三上半学期就找到了外企实习工作,半年时间,我是怎么逆袭的?
  20. 现有的人脸数据库介绍及下载链接

热门文章

  1. DevOps使用教程 华为云(8)代码托管 代码仓库 git协作开发
  2. 图(二):图的邻接矩阵表示
  3. python 判断数字连续_零基础如何自学python? 这些知识点是你进阶的必经之路
  4. Kubernetes(K8s) 1.14.3常用操作命令
  5. 1.5.PHP7.1 狐教程-(PHP开发工具 PHPStorm 配置)
  6. Java 23 种设计模式概述 与 简单工厂模式
  7. Lucene 索引维护 之 删除 与 更新 文档
  8. java sleep唤醒_[JavaEE]如何唤醒Sleep中的线程
  9. 小D课堂 - 新版本微服务springcloud+Docker教程_6-05 高级篇幅之高并发情况下
  10. 小D课堂 - 零基础入门SpringBoot2.X到实战_第8节 数据库操作之整合Mybaties和事务讲解_35、事务介绍和常见的隔离级别,传播行为...