最短路径——Bellman-Ford算法以及SPFA算法
说完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算法的更多相关文章
- 数据结构与算法--最短路径之Bellman算法、SPFA算法
数据结构与算法--最短路径之Bellman算法.SPFA算法 除了Floyd算法,另外一个使用广泛且可以处理负权边的是Bellman-Ford算法. Bellman-Ford算法 假设某个图有V个顶点 ...
- 最短路径:我的理解--SPFA算法
SPFA算法 求单源最短路的SPFA算法的全称是:Shortest Path Faster Algorithm. 最短路径快速算法-SPFA算法是西南交通大学段凡丁于1994年发表的. 适用范围:给定 ...
- Bellman-Ford算法与SPFA算法详解
PS:如果您只需要Bellman-Ford/SPFA/判负环模板,请到相应的模板部分 上一篇中简单讲解了用于多源最短路的Floyd算法.本篇要介绍的则是用与单源最短路的Bellman-Ford算法和它 ...
- Bellman-ford算法、SPFA算法求解最短路模板
Bellman-ford 算法适用于含有负权边的最短路求解,复杂度是O( VE ),其原理是依次对每条边进行松弛操作,重复这个操作E-1次后则一定得到最短路,如果还能继续松弛,则有负环.这是因为最长的 ...
- 最短路径算法 4.SPFA算法(1)
今天所说的就是常用的解决最短路径问题最后一个算法,这个算法同样是求连通图中单源点到其他结点的最短路径,功能和Bellman-Ford算法大致相同,可以求有负权的边的图,但不能出现负回路.但是SPFA算 ...
- 最短路径问题的Dijkstra和SPFA算法总结
Dijkstra算法: 解决带非负权重图的单元最短路径问题.时间复杂度为O(V*V+E) 算法精髓:维持一组节点集合S,从源节点到该集合中的点的最短路径已被找到,算法重复从剩余的节点集V-S中选择最短 ...
- 最短路径算法之四——SPFA算法
SPAF算法 求单源最短路的SPFA算法的全称是:Shortest Path Faster Algorithm,该算法是西南交通大学段凡丁于1994年发表的. 它可以在O(kE)的时间复杂度内求出源点 ...
- 单源最短路径(3):SPFA 算法
SPFA(Shortest Path Faster Algorithm)算法,是西南交通大学段凡丁于 1994 年发表的,其在 Bellman-ford 算法的基础上加上一个队列优化,减少了冗余的松弛 ...
- 【算法】单元最短路径之Bellman-Ford算法和SPFA算法
SPFA是经过对列优化的bellman-Ford算法,因此,在学习SPFA算法之前,先学习下bellman-Ford算法. bellman-Ford算法是一种通过松弛操作计算最短路的算法. 适用条件 ...
随机推荐
- Git-SSH
终端命令: 1.查看ssh ls -al ~/.ssh 存在则会列出对应的 rsa 2.不存在则生成 ssh-keygem -o -t rsa -C "邮箱" -b 4096 3. ...
- mix-blend-mode 混合模式 background-blend-mode 背景混合模式 isolation:isolate 隔离
css3 mix-blend-mode 混合模式 该属性不仅可以作用于HTML,还可以作用于SVG 兼容性: IE 8~11 Edge 12~14 Firefox 41~47 chrome 45~51 ...
- 最长递增子序列(51Nod - 1134)
20180604 23:18 https://blog.csdn.net/joylnwang/article/details/6766317(写得很用心,膜拜dalao) 给出长度为N的数组,找出这个 ...
- ABAP术语-Database Rollback
Database Rollback 原文:http://www.cnblogs.com/qiangsheng/archive/2008/01/24/1051238.html Operation tha ...
- bootstrap-daterangepicker插件运用
引入:daterangepicker.css.daterangepicker.js.moment.js.moment.min.js 链接:https://files.cnblogs.com/files ...
- jQuery最重要的知识点
1.各种常见的选择器.2.对于属性的操作.[重点] 2.1)获取或设置属性的值: prop(); 2.2 ) 添加.删除.切换样式: addClass/removeClass/toggleClass ...
- CPS---(Cyber-Physical Sytem,信息物理融合系统)
1.CPS定义 CPS是连接计算机虚拟世界与物理现实世界的系统.---We refer to systems that bridge the cyber-world of computing and ...
- 素数环 南阳acm488(回溯法)
素数环 时间限制:1000 ms | 内存限制:65535 KB 难度:2 描述 有一个整数n,把从1到n的数字无重复的排列成环,且使每相邻两个数(包括首尾)的和都为素数,称为素数环. 为了简 ...
- 014---Django的中间件
前戏 我们在前面的课程中已经学会了给视图函数加装饰器来判断是用户是否登录,把没有登录的用户请求跳转到登录页面.我们通过给几个特定视图函数加装饰器实现了这个需求.但是以后添加的视图函数可能也需要加上装 ...
- java 解析xml 多命名空间问题
先贴段有命名空间的xml吧.. <feed xmlns:im="http://itunes.apple.com/rss" xmlns="http://www.w3. ...