最短路径——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算法是一种通过松弛操作计算最短路的算法. 适用条件 ...
随机推荐
- Controller类的方法上的RequestMapping一定要写在Controller类里吗?
转载请标明出处: https://blog.csdn.net/forezp/article/details/80069961 本文出自方志朋的博客 使用Spring Cloud做项目的同学会使用Fei ...
- SQL on&where&having
on.where.having这三个都可以加条件的子句中,on是最先执行,where次之,having最后.有时候如果这先后顺序不影响中间结果的话,那最终结果是相同的.但因为on是先把不符合条件的记录 ...
- vue里使用百度地图
最近公司项目里要用到百度地图,然后查阅了一些资料,并总结了下: 首先呢,由于本公司使用的是百度离线地图,那么我们首先需要将百度地图离线包放置static静态文件目录下(我的离线地图包名是“baidu_ ...
- POJ 1066--Treasure Hunt(判断线段相交)
Treasure Hunt Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 7857 Accepted: 3247 Des ...
- oracle-sql优化-通过分组和缓存减少不必要的读
环境:aix 7.1,oracle12.1.0.2 cdb 优化前SQL select * from (select row_.*, rownum rownum_ from (select '弱覆盖' ...
- js-关于iframe:从子页面给父页面的控件赋值方法
项目中我们经会用到iframe,可能还会把iframe里的数值赋值给父页面空间. 接下来我们来说说有关于iframe赋值给父页面的方法. 1.子页面iframe给父页面的控件赋值方法. parent. ...
- js中split()和join()的用法
Split()方法:把一个字符串分割成字符串数组 如上所示:把字符串a按空格分隔,得3个字符串数组. 在如: var a=”hao are you” a.split(“”); 得到[h,a,o, ...
- php 删除富文本编辑器保存内容中的其他代码(保留中文)
$str = '<p><p style="ve:"">测试筛选文本域内的中文 </p><p sty;"> ...
- scala成长之路(2)对象和类
scala提供了一种特殊的定义单例的方法:object关键字 scala> object Shabi{ | val age = 0 | val name = "shabi" ...
- CentOS下安装pip
CentOS下安装pip 通常情况下使用命令: yum -y install pip 也有可能报错,无法安装.这是应该使用第二种方法. 1.首先需要先安装扩展源EPEL: yum -y install ...