求最短路径算法之SPAF算法。
关于求最短路径:
求最短路径的算法有许多种,除了排序外,恐怕是OI界中解决同一类问题算法最多的了。最熟悉的无疑是Dijkstra(不能求又负权边的图),接着是Bellman-Ford,它们都可以求出由一个源点向其他各点的最短路径;如果我们想要求出每一对顶点之间的最短路径的话,还可以用Floyd-Warshall。
关于松弛:
松弛操作的原理是著名的定理:“三角形两边之和大于第三边”,在信息学中我们叫它三角不等式。所谓对i,j进行松弛,就是判定是否d[j]>d[i]+w[i,j],如果该式成立则将d[j]减小到d[i]+w[i,j],否则不动。
SPFA简介:
求单源最短路的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无法处理带负环的图)
SPFA算法过程图解:
如下图求从源点a到其他点的最短路径:
1、首先建立起始点a到其余各点的最短路径表格,将源点元素(a)入队列:
2、源点元素(a)出队,对以a为起始点的所有边的终点依次进行松弛操作(此处有b,c,d三个点),此时路径表格状态为:
注意这里b,c,d都使d[]数组的值变小了,且不在queue队列中,所有入队。
3、队首元素b点出队,对以b为起始点的所有边的终点依次进行松弛操作(此处只有e点),此时路径表格状态为:
4、队首元素c点出队,对以c为起始点的所有边的终点依次进行松弛操作(此处有e,f两个点),此时路径表格状态为:
注意此时e在队列中,所以e不用再次入队列形成 d e f e这种队列形式,如这样会增加冗余运算。
5、队首元素d点出队,对以d为起始点的所有边的终点依次进行松弛操作(此处只有g这个点),此时路径表格状态为:
6、队首元素e点出队,对以e为起始点的所有边的终点依次进行松弛操作(此处有g这个点),因为d[e]+map[e][g](e到g点的距离)>d[g],故g不进队列,再说g本来就在队列里面了-,-此时队列的状态:
7、队首元素f点出队,对以f为起始点的所有边的终点依次进行松弛操作(此处有d,e,g三个点),此时路径表格状态为:
d点使路径表d[d]的值变大了,不如队列; e,f的最短路径估值变小了,e在队列中存在,f不存在。因此e不用入队了,f要入队。
8、队首元素g点出队,对以g为起始点的所有边的终点依次进行松弛操作(此处只有b点),此时路径表格状态为:
9、队首元素e点出队,对以e为起始点的所有边的终点依次进行松弛操作(此处只有g这个点),此时路径表格状态为:
d[e]+map[e][g]>d[g],故g不入队列
10、队首元素b点出队,对以b为起始点的所有边的终点依次进行松弛操作(此处只有e这个点),此时路径表格状态为:
当队列为空了,即计算出了从源点带所有点的最短距离, 由上表知:
a到b的最短路径是17;
关于算法能否结束?
由上面的演示我们知道,当queue为空的时候,我们就得出结果了。那是否存在queue不为空的时候呢,答案是肯定的。
对于不存在负权回路的图来说,上述算法是一定会结束的。因为算法在反复优化各个最短路径长度,总有一个时刻会进入“无法再优化”的局面,此时一旦队列读空,算法就结束了。然而,如果图中存在一条权值为负的回路,就糟糕了,算法会在其上反复运行(因为d[]加上一个负数肯定变下了,所以在有负环的情况下,会不断有数进入队列),通过“绕圈”来无休止地试图减小某些相关点的最短路径值。假如我们不能保证图中没有负权回路,一种“结束条件”是必要的。这种结束条件是什么呢?
思考Bellman-Ford算法,它是如何结束的?显然,最朴素的Bellman-Ford算法不管循环过程中发生了什么,一概要循环|V|-1遍才肯结束。凭直觉我们可以感到,SPFA算法“更聪明一些”,就是说我们可以猜测,假如在SPFA中,一个点进入队列——或者说一个点被处理——超过了|V|次,那么就可以断定图中存在负权回路了。
参考资料:
博客:http://blog.csdn.net/kg_second/article/details/7894298
www.cnblogs.com/zgmf_x20a/archive/2008/12/18/1357737.html
求最短路径算法之SPAF算法。的更多相关文章
- 求最短路径的三种算法: Ford, Dijkstra和Floyd
Bellman-Ford算法 Bellman-Ford是一种容易理解的单源最短路径算法, Bellman-Ford算法需要两个数组进行辅助: dis[i]: 存储顶点i到源点已知最短路径 path[i ...
- JS实现最短路径之弗洛伊德(Floyd)算法
弗洛伊德算法是实现最小生成树的一个很精妙的算法,也是求所有顶点至所有顶点的最短路径问题的不二之选.时间复杂度为O(n3),n为顶点数. 精妙之处在于:一个二重初始化,加一个三重循环权值修正,完成了所有 ...
- C++迪杰斯特拉算法求最短路径
一:算法历史 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题.迪杰斯特拉算法主要特点是以 ...
- 《算法导论》读书笔记之图论算法—Dijkstra 算法求最短路径
自从打ACM以来也算是用Dijkstra算法来求最短路径了好久,现在就写一篇博客来介绍一下这个算法吧 :) Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的 ...
- Dijkstra算法求最短路径(java)(转)
原文链接:Dijkstra算法求最短路径(java) 任务描述:在一个无向图中,获取起始节点到所有其他节点的最短路径描述 Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到 ...
- js迪杰斯特拉算法求最短路径
1.后台生成矩阵 名词解释和下图参考:https://blog.csdn.net/csdnxcn/article/details/80057574 double[,] arr = new double ...
- 最短路径算法之四——SPFA算法
SPAF算法 求单源最短路的SPFA算法的全称是:Shortest Path Faster Algorithm,该算法是西南交通大学段凡丁于1994年发表的. 它可以在O(kE)的时间复杂度内求出源点 ...
- 最短路径算法之Dijkstra算法(java实现)
前言 Dijkstra算法是最短路径算法中为人熟知的一种,是单起点全路径算法.该算法被称为是“贪心算法”的成功典范.本文接下来将尝试以最通俗的语言来介绍这个伟大的算法,并赋予java实现代码. 一.知 ...
- 图中最短路径算法(Dijkstra算法)(转)
1.Dijkstra 1) 适用条件&范围: a) 单源最短路径(从源点s到其它所有顶点v); b) 有向图&无向图(无向图可以看作(u,v),(v,u)同属于边集E ...
随机推荐
- 跑openstack命令错误【You must provide a username via either -...】
openstack设置环境,openstack该服务已经启动.当运行openstack当一个命令,如nova service list例如,下面的错误信息 You must provide a use ...
- Windows台cocos2d-x 3.2下载一个新的项目,创造的过程
首先,左右cocos2d-x于windows下一个Android建筑环境, 引用一个网友这个博客<cocos2d-x 3.0rc开发指南:Windows下Android环境搭建>. 这里简 ...
- 【leetcode】Clone Graph(python)
类似于二叉树的三种遍历,我们能够基于遍历的模板做非常多额外的事情,图的两种遍历,深度和广度模板相同也能够做非常多额外的事情,这里举例利用深度优先遍历的模板来进行复制,深度优先中,我们先訪问第一个结点, ...
- hdu2844 & poj1742 Coin ---多重背包--两种方法
意甲冠军:你有N种硬币,每个价格值A[i],每个号码C[i],要求. 在不超过M如果是,我们用这些硬币,有多少种付款的情况下,.那是,:1,2,3,4,5,....,M这么多的情况下,,你可以用你的硬 ...
- SpringMVC + Spring 3.2.14 + Hibernate 3.6.10
SpringMVC + Spring 3.2.14 + Hibernate 3.6.10 集成详解 注:此文档只说明简单的框架集成,各个框架的高级特性未涉及,刚刚接触框架的新人可能需要参考其他资料. ...
- 他们控制的定义--让背景颜色变化ViewPager逐步幻灯片
转载请注明出处.谢谢~ 今天想说一个简单但很好的效果达到.代码是绝对简单,达到绝对easy,就是你可能想不到而已. 不多说,上效果图. 第一个效果是仿最美应用的滑动颜色变化,第二个是我项目中要用的效果 ...
- [ACM] hdu 1285 确定比赛 (拓扑排序)
确定比赛 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submi ...
- "错: void 值不被忽略,因为预期"解决
在C陷阱与缺陷,实现assert什么时候,在这个过程很聪明,化为一个表达式,在当条件为假时就会调用_assert_error报错并终止程序. 刚開始_assert_error 的返回值类型是 void ...
- Ajax.BeginForm的异步提交数据 简介
Html.BeginForm与Ajax.BeginForm都是MVC架构中的表单元素,它们从字面上可以看到区别,即Html.BeginForm是普通的表单提交,而Ajax.BeginForm是支持异步 ...
- crawler_工具类_RegexUtils_正则帮助类
package com.cph.crawler.core.utils; import java.util.ArrayList; import java.util.List; import java.u ...