说完dijkstra算法,有提到过朴素dij算法无法处理负权边的情况,这里就需要用到Bellman-Ford算法,抛弃贪心的想法,牺牲时间的基础上,换取负权有向图的处理正确。


单源最短路径

Bellman-Ford算法

思维

一张有向图,有n个点,m条边,用dis[]数组保存源点到各点的最短距离,可以通过对边进行n-1次的遍历,当其满足dis[v]>dis[u]+w的时候,就对其进行松弛更新,重复n-1次以后就能得到答案,如果n-1次以后还能继续更新,则可以判断图中出现了负权环,思路非常简短。


举例演算

我们依然设置1为源点,为了直观展现算法思路,设定边的输入顺序如下:

2 4 2

3 4 3

1 2 1

1 3 2

次序 dis[1] dis[2] dis[3] dis[4]
初始化 0
1 0 1 2
2 0 1 2 3
3 0 1 2 3

第一次遍历中,由于点2和点4的距离都是无限大,无法松弛,点3和点4同理。点1和点2,点1和点3符合松弛条件,更新。第二次遍历中,点2和点4就可以松弛更新了,点3和点4也是同理。第三次遍历是一次无用遍历,所有边都已经松弛过了。

由此也能够看出,其实不用进行n-1的遍历就可以得到答案了,可以加入一个bool标记来提前结束这个循环过程。


代码实现

时间复杂度O(NM)

#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue> using namespace std; const int MAX = 1000; int u[MAX], v[MAX], w[MAX], dis[MAX];
int n, m; void Ford(int s) {
for (int i = 1; i <= n; i++) dis[i] = 0x7fffffff;
dis[s] = 0;
for (int i = 0; i < n - 1; i++) {
bool check = 0;
for (int j = 0; j < m; j++) {
if ((dis[v[j]] >= 0x7fffffff) && (dis[u[j]] >= 0x7fffffff)) continue;
else {
if (dis[v[j]] > dis[u[j]] + w[j]) {
dis[v[j]] = dis[u[j]] + w[j];
check = 1;
}
}
}
if (!check) break;
}
} int main() {
cin >> n >> m;
for (int i = 0; i < m; i++) cin >> u[i] >> v[i] >> w[i];
int x;
cin >> x;
Ford(x);
cout << endl;
for (int i = 1; i <= n; i++) {
if (dis[i] > 100000) cout << "none" << " ";
else cout << dis[i] << " ";
}
cout << endl;
return 0;
}

SPFA算法

思维

SPFA算法就是用双端队列优化过的Bellman-Ford算法,初始时将源点加入队列。每次选出队首结点,对其的所有出边进行松弛更新,更新成功的点加入队列,同一个结点可能被多次更新,但是同一个结点只能在同时在队列中出现一个,重复这个操作直到队列为空。这里其实有点像是上一篇dij堆优化代码的思路了。只是缺少了贪心。


代码实现

#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
sing namespace std; const int MAX = 1000; int h[MAX * 2], nxt[MAX * 2], to[MAX * 2], co[MAX * 2], dis[MAX], k = 0, book[MAX];
int n, m; void insert(int u, int v, int c) {
nxt[++k] = h[u];
h[u] = k;
to[k] = v;
co[k] = c;
} void SPFA(int s) {
for (int i = 1; i <= n; i++) {
book[i] = 0;
dis[i] = 0x7fffffff;
}
queue<int> que;
que.push(s);
dis[s] = 0;
book[s] = 1;
while (!que.empty()) {
int cur = que.front();
for (int i = h[cur]; i; i = nxt[i]) { if (dis[to[i]] > dis[cur] + co[i]) {
dis[to[i]] = dis[cur] + co[i];
if (book[to[i]] == 0) {
que.push(to[i]);
book[to[i]] = 1;
}
}
}
que.pop();
book[cur] = 0;
}
} int main() {
cin >> n >> m;
int u, v, w;
for (int i = 0; i < m; i++) {
cin >> u >> v >> w;
insert(u, v, w);
}
int x;
cin >> x;
SPFA(x);
for (int i = 1; i <= n; i++) {
if (dis[i] > 100000) cout << "none" << " ";
else cout << dis[i] << " ";
}
cout << endl;
return 0;
}

最短路径——Bellman-Ford算法以及SPFA算法的更多相关文章

  1. 数据结构与算法--最短路径之Bellman算法、SPFA算法

    数据结构与算法--最短路径之Bellman算法.SPFA算法 除了Floyd算法,另外一个使用广泛且可以处理负权边的是Bellman-Ford算法. Bellman-Ford算法 假设某个图有V个顶点 ...

  2. 最短路径:我的理解--SPFA算法

    SPFA算法 求单源最短路的SPFA算法的全称是:Shortest Path Faster Algorithm. 最短路径快速算法-SPFA算法是西南交通大学段凡丁于1994年发表的. 适用范围:给定 ...

  3. Bellman-Ford算法与SPFA算法详解

    PS:如果您只需要Bellman-Ford/SPFA/判负环模板,请到相应的模板部分 上一篇中简单讲解了用于多源最短路的Floyd算法.本篇要介绍的则是用与单源最短路的Bellman-Ford算法和它 ...

  4. Bellman-ford算法、SPFA算法求解最短路模板

    Bellman-ford 算法适用于含有负权边的最短路求解,复杂度是O( VE ),其原理是依次对每条边进行松弛操作,重复这个操作E-1次后则一定得到最短路,如果还能继续松弛,则有负环.这是因为最长的 ...

  5. 最短路径算法 4.SPFA算法(1)

    今天所说的就是常用的解决最短路径问题最后一个算法,这个算法同样是求连通图中单源点到其他结点的最短路径,功能和Bellman-Ford算法大致相同,可以求有负权的边的图,但不能出现负回路.但是SPFA算 ...

  6. 最短路径问题的Dijkstra和SPFA算法总结

    Dijkstra算法: 解决带非负权重图的单元最短路径问题.时间复杂度为O(V*V+E) 算法精髓:维持一组节点集合S,从源节点到该集合中的点的最短路径已被找到,算法重复从剩余的节点集V-S中选择最短 ...

  7. 最短路径算法之四——SPFA算法

    SPAF算法 求单源最短路的SPFA算法的全称是:Shortest Path Faster Algorithm,该算法是西南交通大学段凡丁于1994年发表的. 它可以在O(kE)的时间复杂度内求出源点 ...

  8. 单源最短路径(3):SPFA 算法

    SPFA(Shortest Path Faster Algorithm)算法,是西南交通大学段凡丁于 1994 年发表的,其在 Bellman-ford 算法的基础上加上一个队列优化,减少了冗余的松弛 ...

  9. 【算法】单元最短路径之Bellman-Ford算法和SPFA算法

    SPFA是经过对列优化的bellman-Ford算法,因此,在学习SPFA算法之前,先学习下bellman-Ford算法. bellman-Ford算法是一种通过松弛操作计算最短路的算法. 适用条件 ...

随机推荐

  1. 【oracle使用笔记3】sql查询遇到的若干问题总结

    在整个开发过程中,sql查询操作的频率比较高,在不同的业务场景下会出现不同的查询需求,以下是我在项目中遇到的查询需求,总结一下. [查询一]:取查询出的第一条数据 select * from (sel ...

  2. C++的抽象类、虚函数、虚基类和java的抽象类和接口

    简单整理如下: C++虚函数 == java普通函数 C++纯虚函数 == java抽象函数 C++抽象类 == java抽象类 C++虚基类(全都是纯虚函数) == java接口

  3. 【TOJ 1545】Hurdles of 110m(动态规划)

    描述 In the year 2008, the 29th Olympic Games will be held in Beijing. This will signify the prosperit ...

  4. ABAP术语-Lock Argument

    Lock Argument 原文:http://www.cnblogs.com/qiangsheng/archive/2008/02/29/1085717.html Locked fields in ...

  5. 单机安装hadoop+hive+presto

    系统环境 在个人笔记本上使用virtualbox虚拟机 os:centos -7.x86-64.everything.1611  ,内核 3.10.0-514.el7.x86_64 注:同样可以使用r ...

  6. TP3.2.3 接入阿里sms 短信接口

    阿里云短信接口 配置文件 config.php //阿里大鱼 'Ali_SMS' =>array( 'sms_temp' =>'短信模板', 'sms_sign' =>'签名', ' ...

  7. python 装饰器 (多个装饰器装饰一个函数---装饰器前套一个函数)

    #带参数的装饰器 #500个函数 # import time # FLAGE = False # def timmer_out(flag): # def timmer(func): # def inn ...

  8. uva 12096 - The SetStack Computer(集合栈)

    例题5-5 集合栈计算机(The Set Stack Computer,ACM/ICPC NWERC 2006,UVa12096) 有一个专门为了集合运算而设计的"集合栈"计算机. ...

  9. xss挑战赛小记 0x03(xssgame)

    0x00 继续做xss吧 这次是xssgame 地址 http://www.xssgame.com/ 一共八关 学到了很多东西 0x01 啥也没有 <svg/onload="alert ...

  10. javascript对象转为字符串

    function getStringTime(time){ //年 year = time.getFullYear(); //月 month = time.getMonth() if(String(m ...