最短路径——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算法是一种通过松弛操作计算最短路的算法. 适用条件 ...
随机推荐
- MySQL表结构(含数据类型、字段备注注释)导出成Excel
方法一: 1.用的是Navicat Premium,可以换成任意图形化客户端 SELECT COLUMN_NAME 列名, COLUMN_TYPE 数据类型, DATA_TYPE 字段类型, CHAR ...
- ref、refs使用的注意事项
ref是被用来给元素或子组件注册引用信息.引用信息将注册在父组件的 $refs 对象身上.如果在普通的DOM元素身上使用,引用指向就是DOM元素:如果用在子组件身上,引用就是指向组件实例. 当v-fo ...
- Zabbix——部署(DB与web一体)
前提条件: CentOS连接网络并可以正常访问网络 DNS设置完成,可以Ping同外网域名 安装数据库为8.0版本 关闭防火墙 如果需要搭建分离式请见:DB与Web分离 &DB.web.age ...
- Mit6.824 Lab1-MapReduce
前言 Mit6.824 是我在学习一些分布式系统方面的知识的时候偶然看到的,然后就开始尝试跟课.不得不说,国外的课程难度是真的大,一周的时间居然要学一门 Go 语言,然后还要读论文,进而做MapRed ...
- @staticmethod怎么用?
早上起来写个小demo, 类中写了个方法, pycharm给这个方法加上了莫名其妙的波浪线, 对于一个有代码洁癖的人来说, 完全不能忍, 来看看为什么. 问题重现 pycharm的提示 上面说了, 这 ...
- maven-认识
1.认识maven maven是强大的项目构建工具,也是依赖管理工具 使用maven前提是安装JDK maven非常重要配置文件:setting.xml 3.maven工程 maven工程的约束: 主 ...
- ThinkPHP框架目录的介绍
library目录 Think目录 mvc
- Python3 函数return
# def logger(): # f = open("loge.txt","a") # f.write("2017-09-15 exec funct ...
- springmvc 配置多视图(jsp,freemarker,HTML等)
SpringMVC 的 Controller 可以返回各种各样的视图.比如 JSP, JSON, Velocity, FreeMarker, XML, PDF, Excel, 还有Html字符流 等等 ...
- c# string.format和tostring()
字符 说明 示例 输出 C 货币 string.Format("{0:C3}", 2) $2.000 D 十进制 string.Format("{0:D3}", ...