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. Codeforces 821E Okabe and El Psy Kongroo(矩阵快速幂)

    E. Okabe and El Psy Kongroo time limit per test 2 seconds memory limit per test 256 megabytes input ...

  2. [Leetcode] subsets ii 求数组所有的子集

    Given a collection of integers that might contain duplicates, S, return all possible subsets. Note: ...

  3. BZOJ3289 Mato的文件管理 【莫队 + 树状数组】

    3289: Mato的文件管理 Time Limit: 40 Sec  Memory Limit: 128 MB Submit: 3964  Solved: 1613 [Submit][Status] ...

  4. sqlserver数据库迁移

    本篇我们将利用DMA一步一步实现SQL Server 的迁移.帮助大家理解现在的SQL Server与新版本的融合问题,同时需要我们做哪些操作来实现新版本的升级或者迁移. SQL Server 迁移 ...

  5. HDU 5665

    Lucky Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submi ...

  6. word使用宏 在文章中插入源代码进行排版

    1.宏的代码如下. Sub 设置代码表格() ' author: code4101 ' 设置代码表格 宏 ' ' ' 背景色为morning的配色方案,RGB为(229,229,229) ) With ...

  7. 图论:Gale-Shapley算法

    Gale-Shapley算法又叫做延迟认可算法,它可以解决这么一个问题 一共有N位男士和N位女士 每位男士对每位女士都有一个好感度,让他们结合成为N对夫妻,要求男士优先表白,最后问结合情况 第一轮,每 ...

  8. kafka+flume+HDFS日志采集项目框架

    1,项目图如下: 2, 实现过程 启动HDFS: sbin/start-dfs.sh 启动zookeeper(三台): bin/zkServer.sh start 启动kafka(三台): root@ ...

  9. bzoj2453/2120 数颜色

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2120 http://www.lydsy.com/JudgeOnline/problem.ph ...

  10. Ubuntu 15.10 安装比特币客户端

    下载 git clone https://github.com/bitcoin/bitcoin.git cd bitcoin ./autogen.sh 安装依赖包: ++-dev sudo apt-g ...