SPFA(Shortest Path Faster Algorithm):

一:基本算法

  在求解单源最短路径的时候,最经典的是 Dijkstra 算法,但是这个算法对于含有负权的图就无能为力了,而 Bellman - Ford 算法的复杂度又过于高,这时 SPFA就应运而生了. SPFA 在 Bellman - Ford 算法的基础上进行了改进,使其能够在计算带有负权的图的单源最短路径的基础上,时间复杂度大幅降低.

  众所周知 Bellman -Ford 算法会对每条边进行 n - 1 次检查,但是在这些检查过程中,有许多检查是没有必要的.事实上,唯一应该检查的边存在一个特点:这些边的起点在上一次处理时到源点的距离发生了变化,即松弛成功的边的终点.既然如此,那么就可以对算法进行优化,即每遍只处理特殊的点,这些点是上一次在松弛过程中某条边的终点.设立一个先进先出的队列来维护这些待处理的点,优化时每次取出队首节点 u, 并且对所有从点 u 出发的边进行松弛操作,对于每条边的终点 v,如果以点 v 为终点的边松弛成功, 且 v 不在队列内, 就将点 v 加入队尾.这样不断从对列取出节点来进行松弛操作,直至队列空为止.这个算法保证只要最短路径存在, SPFA 必定能求出最小值.

  SPFA同样可以判断负环,如果某个点弹出队列的次数超过 N - 1 次,则存在负环.对于存在负环的图,是无法计算出单源最短路径的.

二:伪代码

  在以下说明中, inque[] 记录点是否在队列中, 使用链式前向星存图, 结果保留在 dist[] 中.

  (1):初始化,源的距离 dist[s] 设为 0, 其他点的距离设置为 INF, 新建一个队列, 将源点 s 入队, 标记源点 s 已经在对列中.

  (2):从队首取出一个点 top, 标记top出队, top 出队的次数加 1,并对这个次数检查, 如果大于 n, 说明出现负环, 结束算法. 否则遍历从点 top 出发的边, 如果边 k 的终点 to 的 dist[] 可以更新, 即 dist[ edge[k].to ] > dist[top] + edge[k].w, 则更新 dist[ edge[k].to ] = dist[top] + edge[k].w, 检查 to 是否在队列内, 如果不在则加入队列.

  (3)重复执行步骤(2), 直至队列为空.

三:以图为列

初始化队列、图和 dist[] 数组:

1.选择队列首部的点 “5”,对从此点出发的边 <"5", "3"> 和  <"5", "4"> 进行松弛:

2.选择队列首部的点 “3”,对从此点出发的边 <"3", “4”> 进行松弛, 松弛失败, 点 ”4“ 不会再次加入队列:

3.选择队列首部的点 “4”,对从此点出发的边 <"4", "1"> 和 <"4", "6">进行松弛:

4.选择队列首部的点 “1”,对从此点出发的边 <"1", '2"> 和 <"1", "6">进行松弛, 这里点”6“已经在队列内了,所以点 “6” 不会加入队列.

5.选择队列首部的点 “6”,对从此点出发的边<"6", "2"> 和 <"6", "5"> 进行松弛,.对边 <"6", "5"> 松弛失败, 虽然点 “5” 不在队列内, 但也不应该加入队列.

6.选择队列首部的点 “2”,对从此点出发的边<"2", "3"> 和 <"2", "5"> 进行松弛,.对边 <"2", "5"> 松弛失败, 点 “5” 不应该加入队列.

7.选择队列首部的点 “3”,对从此点出发的边<"3", "4"> 进行松弛,.且对边 <"3", "4"> 松弛失败, 此时队列为空算法结束.

四:代码

 const int MAXN = ;
const int MAXE = ;
const int INF = INT_MAX;
int dist[MAXN + ];// dist[i] 表示点 i 到源点 s 的最短距离 int head[MAXN + ];//链式前向星存图
struct NODE { int to; int w; int next; };
NODE edge[MAXE]; bool SPFA(int n, int s) {//s 为源点 n 为总的点数
for(int i = ; i <= n; i++) dist[i] = INF;//初始化
dist[s] = ;
queue<int> rex;//保存待优化的节点
rex.push(s);//从源点 s 开始优化s
bool inque[MAXN + ] = { false };//inque[i] = false 表示点 i 在队列内
inque[s] = true;
int outque[MAXN + ] = { };//记录每个点出对列的次数
while(!rex.empty()) {
int top = rex.front();//取队首的点为待拓展节点
rex.pop();
inque[top] = false;
outque[top] ++;
if(outque[top] > n) return false;//存在负环
for(int k = head[top]; k != -; k = edge[k].next) {//对从当前点出发的所有边进行松弛操作
if(dist[top] != INF && dist[ edge[k].to ] > dist[top] + edge[k].w) {
dist[ edge[k].to ] = dist[top] + edge[k].w;
if(!inque[ edge[k].to ]) {//如果当前边另外一端的顶点不在队列内,则加入到队尾
rex.push( edge[k].to );
inque[ edge[k].to ] = true;
}
}
}
}
return true;
}

参考书籍 <<图论及应用>> 和网上部分资料.

SPFA解决单源最短路径的更多相关文章

  1. SPFA求单源最短路径

    序 求最短路径的算法有很多,各有优劣. 比如Dijkstra(及其堆(STL-priority_queue)优化),但是无法处理负环的情况: 比如O(n^3)的Floyd算法:比如Bellman-Fo ...

  2. Dijkstra算法解决单源最短路径

    单源最短路径问题:给定一个带权有向图 G = (V, E), 其中每条边的权是一个实数.另外,还给定 V 中的一个顶点,称为源.现在要计算从源到其他所有各顶点的最短路径长度.这里的长度是指路上各边权之 ...

  3. Poj 1860 Currency Exchange(Bellman-Ford,SPFA解单源最短路径问题)

    一.题意 有多个货币交易点,每个只能互换两种货币,兑换的汇率不同,并收取相应的手续费.有N种货币,假定你拥有第S中,数量为V,有M个兑换点.问你能不能通过兑换操作使你最后拥有的S币比起始的时候多. 二 ...

  4. Dijkstra 单源最短路径算法

    Dijkstra 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法,由计算机科学家 Edsger Dijkstra 于 1956 年 ...

  5. Bellman-Ford 单源最短路径算法

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

  6. 单源最短路径-迪杰斯特拉算法(Dijkstra's algorithm)

    Dijkstra's algorithm 迪杰斯特拉算法是目前已知的解决单源最短路径问题的最快算法. 单源(single source)最短路径,就是从一个源点出发,考察它到任意顶点所经过的边的权重之 ...

  7. matlab练习程序(单源最短路径Dijkstra)

    图的相关算法也算是自己的一个软肋了,当年没选修图论也是一大遗憾. 图像处理中,也有使用图论算法作为基础的相关算法,比如图割,这个算法就需要求最大流.最小割.所以熟悉一下图论算法对于图像处理还是很有帮助 ...

  8. 【算法】单源最短路径和任意两点最短路径总结(补增:SPFA)

    [Bellman-Ford算法] [算法]Bellman-Ford算法(单源最短路径问题)(判断负圈) 结构: #define MAX_V 10000 #define MAX_E 50000 int ...

  9. 基于visual Studio2013解决算法导论之043单源最短路径dijstra矩阵

     题目 单源最短路径dijstra矩阵 解决代码及点评 // 26单源最短路径dijstra矩阵.cpp : 定义控制台应用程序的入口点. // #include <iostream> ...

随机推荐

  1. HDU 4776 Ants(Trie+优先队列)

    Ants Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others) Total S ...

  2. 【题解】CQOI2017老C的方块

    网络流真的是一种神奇的算法.在一张图上面求感觉高度自动化的方案一般而言好像都是网络流的主阵地.讲真一开始看到这道题也有点懵,题面很长,感觉很难的样子.不过,仔细阅读了题意之后明白了:我们所要做的就是要 ...

  3. HDU 多校对抗赛 B Balanced Sequence

    Balanced Sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  4. 怎么让Intellj Idea 把数据库的表映射成hibernate的domain对象

    步骤如下: 第一步:连接数据源: 点击:idea右边的database.如下图所示: 或者你依次点击:view-->Tool windows--->database 然后你将看在如下点击下 ...

  5. TCP ------ TCP创建服务器中出现的套接字

    在服务器端,socket()返回的套接字用于监听(listen)和接受(accept)客户端的连接请求.这个套接字不能用于与客户端之间发送和接收数据. accept()接受一个客户端的连接请求,并返回 ...

  6. tomcat内存配置及配置参数详解

    1.jvm内存管理机制: 1)堆(Heap)和非堆(Non-heap)内存 按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配.堆是在 Java 虚拟 ...

  7. Spring 学习笔记(二)

      一.Spring 中的bean配置 –配置形式:基于 XML 文件的方式:基于注解的方式 –Bean 的配置方式:通过全类名(反射).通过工厂方法(静态工厂方法 & 实例工厂方法).Fac ...

  8. 汕头市队赛 SRM 06 C 秀恩爱

    C 秀恩爱 SRM 06 背景&&描述         KPM坐在直升机上俯瞰小渔村景象.         渔村可看作二维平面,密密麻麻地到处都是单身狗,KPM当前所在坐标为(sx,s ...

  9. 金山中学 rugular SRM 04 ——纪念我的第一次Ak

    虽然只是一场比较简单的比赛 但奈何我也比较弱啊.... T1 一道计算概率的题目 T SRM 04 描述 给个长度为 n 的数列,每次操作能将数列打乱(RandomShuffle),问在期望下需要多少 ...

  10. python 文件操作 r w a

    python基础-文件操作   一.文件操作 对文件操作的流程 打开文件,得到文件句柄并赋值给一个变量 通过句柄对文件进行操作 关闭文件       打开文件时,需要指定文件路径和以何等方式打开文件, ...