最短路径算法之四——SPFA算法
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算法相关推荐
- #1093 : 最短路径·三:SPFA算法(邻接表)
#1093 : 最短路径·三:SPFA算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 万圣节的晚上,小Hi和小Ho在吃过晚饭之后,来到了一个巨大的鬼屋! 鬼屋中一共 ...
- 【最短路径】:Dijkstra算法、SPFA算法、Bellman-Ford算法和Floyd-Warshall算法
求最短路径最常用的算法有: Dijkstra算法.SPFA算法.Bellman-Ford算法和Floyd-Warshall算法. Dijkstra算法.SPFA算法.Bellman-Ford算法这三个 ...
- 图论-最短路径--3、SPFA算法O(kE)
SPFA算法O(kE) 主要思想是: 初始时将起点加入队列.每次从队列中取出一个元素,并对所有与它相邻的点进行修改,若某个相邻的点修改成功,则将其入队.直到队列为空时算法结束. 这个算 ...
- 题目1008:最短路径问题(SPFA算法)
问题来源 http://ac.jobdu.com/problem.php?pid=1008 问题描述 给定一个G(V,E)有向图,起点s以及终点t,求最短路径. 问题分析 典型的单源最短路径问题,可以 ...
- 最短路径问题(Floyd算法、Dijkstra算法、Bellman-Ford算法、SPFA算法)
导入 最短路径问题是指在一幅带权图中,找出连接两个顶点之间的所有路径中,边权和最短的那一条.如下图就是一幅带权图,边上的数字就代表该边的权值.解决最短路径问题有多种不同的算法,本文将对它们的基本思想与 ...
- 单源最短路 Dijkstra算法 和 SPFA算法
单源最短路 •从一个点出发,到达其他顶点的最短路径的长度. •基本操作:松弛 •d[u]+map[u, v]< d[v]这样的边(u,v)称为紧的(tense),可以对它进行松弛(relax): ...
- floyed算法、dijkstra算法、SPFA算法
转自gzr的博客:https://www.cnblogs.com/TFLS-gzr/p/10381849.html,https://www.cnblogs.com/TFLS-gzr/p/1038746 ...
- 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. :) ...
- BellmanFord算法与SPFA算法
Bellman-Ford Bellman-Ford 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法.该算法由 Richard Be ...
- 常用代码模板3——搜索与图论(Bellman-Ford算法 、spfa 算法、floyd算法、Kruskal算法、染色法、匈牙利算法 )
目录 一.树与图的存储 二.树与图的遍历 (1) 深度优先遍历 -- 模板题 AcWing 846. 树的重心 (2) 宽度优先遍历 -- 模板题 AcWing 847. 图中点的层次 拓扑排序 -- ...
最新文章
- 5-flutter 布局和列表
- 先本地仓库中国添加jar包
- 机器学习笔记:GRU
- 给你汇报Struts2 S2-016漏洞修复的总结
- proxy error: could not proxy request解决方案
- 【Linux】一步一步学Linux——passwd文件详解(107)
- 【招聘(深圳)】轻岁 诚聘.NET Core开发
- 实现两数 交换的三种不同编程方法。
- intellisense_SQL Server IntelliSense的使用和故障排除–适用于SQL Server 2012或更高版本
- 查询同一张表符合条件的某些数据的id拼接成一个字段返回
- 505_TextWatcher可以重复添加
- 山西大学量子计算机,关于量子力学与量子计算机
- 中国 各大银行bankCode 开户行代码和名称 高清银行图标
- 程序员笔试题收集汇总(三)
- 一个成功的BI项目实施需要注意哪些? 1
- This probably means that Tcl wasn‘t installed properly报错
- python如何解析网页的json_python 如何从网页jQuery中爬取JSON中的内容
- 2019 掘安杯 JACTF MISC WP
- 大二上半学期还挂科两门,大三上半学期就找到了外企实习工作,半年时间,我是怎么逆袭的?
- 现有的人脸数据库介绍及下载链接
热门文章
- DevOps使用教程 华为云(8)代码托管 代码仓库 git协作开发
- 图(二):图的邻接矩阵表示
- python 判断数字连续_零基础如何自学python? 这些知识点是你进阶的必经之路
- Kubernetes(K8s) 1.14.3常用操作命令
- 1.5.PHP7.1 狐教程-(PHP开发工具 PHPStorm 配置)
- Java 23 种设计模式概述 与 简单工厂模式
- Lucene 索引维护 之 删除 与 更新 文档
- java sleep唤醒_[JavaEE]如何唤醒Sleep中的线程
- 小D课堂 - 新版本微服务springcloud+Docker教程_6-05 高级篇幅之高并发情况下
- 小D课堂 - 零基础入门SpringBoot2.X到实战_第8节 数据库操作之整合Mybaties和事务讲解_35、事务介绍和常见的隔离级别,传播行为...