一、用途

1. Bellman Ford算法是解决拥有负权边最短路问题的方法之一。还有一种方法是SPFA算法。

2. 二者相比,SPFA算法在效率方面是优于Bellman Ford算法的。但在某些情况下,解决最短路问题只能使用Bellman Ford算法。

3. 时间复杂度:Bellman Ford算法 O(nm)(n是点的个数,m是边数)

SPFA 算法一般是 O(m),最差情况是O(nm)

4.什么情况下只能用Bellman Ford算法而不能用SPFA?

当最短路限制边数的时候,只能使用Bellman Ford。

5.为什么有负权边的时候不能用Dijkstra算法,而用Bellman Ford?

Dijkstra算法不能解决负权边是因为 Dijkstra要求每个点被确定后st[j] = true,dist[j]就是最短距离了,之后就不能再被更新了(一锤子买卖),而如果有负权边的话,那已经确定的点的dist[j]不一定是最短了。

二、算法思路和注意事项

1.算法模板

for(int i=0;i<n-1;i++)
{memcpy(backup,dist,sizeof(dist));for(int j=0;j<m;j++)dist[b]=min(dist[b],backup[a]+w);
}

先开始让dist[]数组初始化为正无穷,dist[1]=0。

遍历n-1次,每次遍历m条边,用每一条边去更新各点到源点的距离。

解释算法:

dist[b]=min(dist[b],backup[a]+w);这段代码什么意思?

这是三角不等式,目的是更新一条有向边右端点的数值。w指的是这条边的权重。a是左端点,b是右端点,取当前dist[b],和前者dist[a]+w,二者的最小值。每一次遍历边的时候后都会更新当前最短路。

memcpy(backup,dist,sizeof(dist));目的是什么?

这段代码是拷贝dist数组里的数据,转移到backup数组。作为备用,目的是使dist数组更新时,不受串联的影响。为什么会导致串联?假设有1,2,3三个点,用1号点更新了2号点。如果不使用backup[]数组,更新3号点时,不会使用2号点的原始数据,而会使用2号点改变之后的数据,造成错误。

外层循环是什么意思?

有个小细节:外层循环1次,跟1号点相隔1条边的点的dist[]值将不是正无穷(会确立此时的最短路)

外层循环2次,跟1号点相隔2条边的点的dist[]值将不是正无穷(会确立此时的最短路)

外层循环n-1次,跟1号点相隔n-1条边的点的dist[]值将不是正无穷(会确立此时的最短路)

希望大家可以画一下,画一下就知道了。

会确立此时的最短路这句话什么意思?

因为会有负权环这个东西的出现,会一直改变之后点的最小路径值。所以此时的最小值不代表是永远的最小值。

何为负权环?

如上图,存在一个环,这个环每经过一次路径值都会减少,为了得到最小路径,这个环会一直走下去,从而之后的点最短路径不会确定。

所以我们解释了为什么外层是遍历n-1次?

是因为总共就n个点,两点间最长的一条边顶多有n-1条边。外层循环n-1次,所有的点的最短路都可以确定。但这个最短路后续会不会变,要看是否有负权环,如果有,那这个最短路只是当前最短路,后续还会变化。如果没有负权环,当前的最短路就是最短路径。

三、例题

给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数。请你求出从 1 号点到 n 号点的最多经过 k 条边的最短距离,如果无法从 1 号点走到 n 号点,输出 impossible。注意:图中可能 存在负权回路 。输入格式
第一行包含三个整数 n,m,k。接下来 m 行,每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。点的编号为 1∼n。输出格式
输出一个整数,表示从 1 号点到 n 号点的最多经过 k 条边的最短距离。如果不存在满足条件的路径,则输出 impossible。数据范围
1≤n,k≤500,
1≤m≤10000,
1≤x,y≤n,
任意边长的绝对值不超过 10000。输入样例:
3 3 1
1 2 1
2 3 1
1 3 3
输出样例:
3

代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=510,M=10010;
struct Edge
{int a,b,w;
}edge[M];
int dist[N],backup[N];
int n,m,k;
void bellman_ford()
{memset(dist,0x3f,sizeof(dist));dist[1]=0;for(int i=0;i<k;i++){memcpy(backup,dist,sizeof(dist));for(int j=0;j<m;j++){int a=edge[j].a,b=edge[j].b,w=edge[j].w;dist[b]=min(dist[b],backup[a]+w);}}
}
int main()
{cin>>n>>m>>k;for(int i=0;i<m;i++){int a,b,w;cin>>a>>b>>w;edge[i]={a,b,w};}bellman_ford();if(dist[n]>=0x3f3f3f3f-5000000) cout<<"impossible"<<endl;else cout<<dist[n]<<endl;return 0;
}

可能存在的疑问:

Q1:外层为什么循环k次?

A:题目中是求从 1 号点到 n 号点的最多经过 k 条边的最短距离。循环k次,就可以知道跟1号点相隔k条边的点的当前最短路。如果循环大于k次,可能由于负权边的存在导致n号点最短路径更新变小。

Q2:为什么dist[n]>=0x3f3f3f3f-5000000,不应该是dist[n]>=0x3f3f3f3f吗?

A:因为遍历边的时候会更新dist值,对于正无穷(0x3f3f3f3f)也会有更新,如果n号点前面一个点是正无穷,每次遍历边的时候(dist[b]=min(dist[b],backup[a]+w);)也会对dist[n]有所修改。因为外层遍历最多500次,边权绝对值不大于10000,所以,如果n号点和1号点没有联系的话,它的dist[n]起码>=0x3f3f3f3f-5000000。

Bellman Ford算法详解相关推荐

  1. bellman ford 算法 判断是否存在负环

    Flyer 目录视图 摘要视图 订阅 微信小程序实战项目--点餐系统        程序员11月书讯,评论得书啦        Get IT技能知识库,50个领域一键直达 关闭 bellman for ...

  2. Matlab人脸检测算法详解

    这是一个Matlab人脸检测算法详解 前言 人脸检测结果 算法详解 源代码解析 所调用函数解析 bwlabel(BW,n) regionprops rectangle 总结 前言 目前主流的人脸检测与 ...

  3. 图论-最短路Dijkstra算法详解超详 有图解

    整体来看dij就是从起点开始扩散致整个图的过程,为什么说他稳定呢,是因为他每次迭代,都能得到至少一个结点的最短路.(不像SPFA,玄学复杂度) 但是他的缺点就是不能处理带负权值的边,和代码量稍稍复杂. ...

  4. C++中的STL算法详解

    1.STL算法详解 STL提供能在各种容器中通用的算法(大约有70种),如插入.删除.查找.排序等.算法就是函数模板,算法通过迭代器来操纵容器中的元素.许多算法操作的是容器上的一个区间(也可以是整个容 ...

  5. 粒子群(pso)算法详解matlab代码,粒子群(pso)算法详解matlab代码

    粒子群(pso)算法详解matlab代码 (1)---- 一.粒子群算法的历史 粒子群算法源于复杂适应系统(Complex Adaptive System,CAS).CAS理论于1994年正式提出,C ...

  6. 基础排序算法详解与优化

    文章图片存储在GitHub,网速不佳的朋友,请看<基础排序算法详解与优化> 或者 来我的技术小站 godbmw.com 1. 谈谈基础排序 常见的基础排序有选择排序.冒泡排序和插入排序.众 ...

  7. 目标检测 RCNN算法详解

    原文:http://blog.csdn.net/shenxiaolu1984/article/details/51066975 [目标检测]RCNN算法详解 Girshick, Ross, et al ...

  8. Twitter-Snowflake,64位自增ID算法详解

    Twitter-Snowflake,64位自增ID算法详解 from: http://www.lanindex.com/twitter-snowflake%EF%BC%8C64%E4%BD%8D%E8 ...

  9. 数据结构与算法详解目录

    数据结构与算法详解是一本以实例和实践为主的图书,主要是经典的数据结构与常见算法案例,来自历年考研.软考等考题,有算法思路和完整的代码,最后提供了C语言调试技术的方法. 后续配套微课视频. 第0章  基 ...

最新文章

  1. DHCP服务器的搭建
  2. 【原创】再见,CVT----记搓人的第一次找实习
  3. 网页设计过程中一般命名规则
  4. hash+set Codeforces Round #291 (Div. 2) C. Watto and Mechanism
  5. 半双工、全双工以太网
  6. iOS应用崩溃日志分析 iOS应用崩溃日志揭秘
  7. 迭代器之输入和输出迭代器
  8. php 特殊字符¥,php正则怎么替换符号
  9. Docker之使用Dockerfile创建定制化镜像(四)--技术流ken
  10. java集成Cplex:Cplex下载、IDEA环境搭建、docker部署
  11. eos 钱包 nacos 安装文档
  12. 一款完整开源的物联网基础平台
  13. 交叉熵、KL散度、Jeffery分歧、JS散度
  14. HTML中的 meta 标签
  15. win10“我们找不到你的相机“,错误代码0xA00F4244<NoCamerasAttached>解决方法
  16. Delphi线程类的使用(1)
  17. 编程之美 一摞烙饼的排序问题
  18. Java系列技术之Mybatis3-钟洪发-专题视频课程
  19. 【Android】【IDE】解决android-studio或IntelliJ-IDEA搜索不到文件内容的问题
  20. 40奇点,天网,计算机的未来

热门文章

  1. greenplum安装(单机环境)
  2. 关于UES跨境支付,这几点你一定要清楚
  3. [攻城狮计划(三)] —— 看门狗定时器
  4. VR(一)ATW ASW
  5. HDMI2.0二进一出切换器方案ASW3642和TS3DV642设计电路对比
  6. 分布式事务(LCN)
  7. win10IE浏览器运行VBScript脚本语言的简单方法
  8. batocera_Batocera新手上路手冊(二):執行遊戲與基本操作說明
  9. Qt收缩窗口动态效果
  10. Azure - 临时磁盘和永久磁盘的区别