Bellman-ford算法详解

article/2025/9/15 18:05:55

什么是Bellman-ford算法

贝尔曼-福特算法(Bellman-Ford)是由理查德·贝尔曼(Richard Bellman)和莱斯特·福特创立的,求解单源最短路径问题的一种算法。其优于Dijkstra的方面是边的权值可以为负数、实现简单,缺点是时间复杂度过高。但它也有特别的用处,一般用于实现通过m次迭代求出从起点到终点不超过m条边构成的最短路径。

Dijkstra算法不能解决带有负权边的问题,而Bellman-ford算法可以解决带有负权边的问题,是求解带负权边的单源最短路问题的经典算法。时间复杂度是O(nm),核心思想是”松弛操作”。解决带负权边的单源最短路问题还有一个常用的算法是SPFA算法,SPFA算法的时间复杂度一般是O(m),最坏是O(nm)。

总结一下就是Dijkstra算法可以解决不带负权边的问题,而对于带有负权边的问题,又有Bellman-ford算法和SPFA解决。

基本思路

首先n次迭代,每一次循环所有边。我们这里用a,b,w表示存在一条从a走到b的边,权重是w。这里存边方式有很多种,可以用邻接表,结构体等。遍历所有边的时候更新一下其他点的距离,和Dijkstra算法类似,用当前这个点更新和它相连的点距离起点的距离。我们这里用dist数组表示每个点到起点的距离,那么更新操作就是dist[b]=min(dist[b],dist[a]+w),这样就可以更新和a相连的b点距离起点的距离,这个更新的过程就是”松弛操作”。忘了说的一点就是在循环所有边的时候,每一次循环要先把dist数组备份一下,防止串联,这个后面会说循环n次之后对所有的边一定满足dist[b]<=dist[a]+w,这个叫”三角不等式”。

这个就是Bellman-ford算法的基本思路。

但是注意如果图中有负权回路的话,最短路就不一定存在了

举个栗子

我们看这个图,红色的数字表示边的权重,我们想求一下1号点到5号点的最短路径,我们从1走到2,2,3,4号点围成了一个圈,圈的总权重是5+-4+-2=-1,那么转一圈长度就会减一,因此我们可以转无穷多圈,转无穷多圈总长度就会变成负无穷,出圈的话还是负无穷。所以说图中存在负权回路的话,从1号点到n号点的距离就会变成负无穷,就不存在了。

所以能求出来最短路的话,图中是没有负权回路的。

而Bellman-ford算法是可以判断图中存不存在负权回路。首先上面的迭代次数是有实际意义的,比如我们迭代了k次,那么我们求的最短距离就是从1号点经过不超过k条边走到n号点的最短距离。所以在第n次迭代的时候又更新了某些边的话,就说明路径中一定存在环,并且是负权回路。因为第n次迭代在不存在负权回路的情况下是遍历到第n号点了,后面是没有点了,如果还能更新,说明路径中存在回路,而且是负权回路。

但是一般找负环是不用Bellman-ford算法,一般是用SPFA算法,这里我们只要知道Bellman-ford算法可以找负权回路即可。

总结

Bellman-ford算法的思路也很简单,直接就是两层循环,内层循环所有边,外层循环就是循环所有边的次数,这个外层循环次数一般是题目控制的。时间复杂度是O(n*m)

案例

给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数

请你求出从 1 号点到 nn 号点的最多经过 kk 条边的最短距离,如果无法从 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

思路

这里要注意的就是我们用结构体去存边的信息,还有一个就是backup数组,这个数组是给dist数组备份的数组。我们在循环所有边的操作中,在每一次循环之前要先把上一次循环后的dist数组备份一下。防止"串联",什么是串联呢?

举个栗子

我们以样例为例

样例是这样一张图,k是1,也就是要求从1号点出发到3号点最多经过1条边的最短距离,通过图很容易就可以看出,最短距离就是3,也就是1号点直接到3号点的距离。

这里我们已经知道最短距离是3了,如果我们不把上一次循环后的dist备份的话会出现什么后果呢?我们根据Bellman-ford算法的步骤,也就是两层循环,外层循环题目控制的是k,也就是1,内层循环所有的边。也就说只会进行一次迭代。我们看一下内层循环的过程,首先一共有三条边,所以内层循环要循环三次。我们看一下内层循环后的结果。注意:这里是没有备份dist数组的结果

1号点

2号点

3号点

内层循环第一次执行

0

内层循环第二次执行

0

1

内层循环第三次执行

0

1

2

可以发现,如果我们没有备份上一次的dist数组的话,最短距离变成了2。内层循环只迭代了一次,但是在更新的过程中会发生”串联”。比如说先更新了2号点,然后我们用2号点更新了3号点距离起点的距离,这样就发生了”串联”,,3号点不能被2号点更新,这样就不满足题目要求了,因为题目要求最多不经过1条边,上面我们说了,迭代次数是有实际意义的,我们迭代1次,那我们求的最短距离就是最多不经过1条边的最短距离。

怎么保证不发生串联呢?我们保证更新的时候只用上一次循环的结果就行。所以我们先备份一下。备份之后backup数组存的就是上一次循环的结果,我们用上一次循环的结果来更新距离。所以我们这样写dist[b]=min(dist[b],backup[a]+w)来更新距离,而不是dist[b]=min(dist[b],dist[a]+w),这样写就会发生上面说的”串联”现象。

代码实现

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=510,M=1e4+10;
int dist[N],backup[N];
int n,m,k;
//这里用结构体存边的信息
struct node
{int a,b,c;
}edg[M];
int 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=edg[j].a,b=edg[j].b,c=edg[j].c;dist[b]=min(dist[b],backup[a]+c);}}return dist[n];
}
int main()
{cin>>n>>m>>k;for(int i=0;i<m;i++){int a,b,c;cin>>a>>b>>c;edg[i]={a,b,c};}//这里不用0x3f3f3f3f是因为防止n号点被负权边更新if(bellman_ford()>0x3f3f3f3f/2)cout<<"impossible";elsecout<<dist[n];return 0;
}

http://chatgpt.dhexx.cn/article/bQ8D9L7g.shtml

相关文章

分形(Fractal)及分形维数(Fractal dimension)

文章目录 1. 分形介绍2. 分形的定义3. 分形维数介绍4. 历史5. 缩放的作用&#xff08;Role of scaling&#xff09;6. D 不是唯一描述符7. 分形表面结构8. 例子8.8 Hausdorff dimension8.8.1 直观概念8.8.2 正式定义8.8.2.1 Hausdorff dimension8.8.2.2 Hausdorff content 8.8.…

Mandelbrot集的最新变化形态一览——MandelBox,Mandelbulb,Burning Ship,NebulaBrot

二维Mandelbrot集——Burning Ship 采用以下迭代公式 (x4-6*x2*y2y4, 4*|x|3*|y|-4*|y|3*|x|) 看不懂的&#xff0c;可以去学习深造了。。。 Mandelbulb 这个3D的Mandelbrot集采用的是以下公式&#xff0c;这应该算是超复数的一种&#xff0c;人称“triplex”&#xff0c;三…

Mandelbrot集Julia集分形的MATLAB实现(分形艺术)

Mandelbrot集Julia集分形的MATLAB实现&#xff08;分形艺术&#xff09; 1 简单Julia集的实现1.1 如何实现更光滑的展示效果&#xff1f; 2 Mandelbrot集的实现3 永恒的细节 本文首发于 matlab爱好者 微信公众号&#xff0c;欢迎关注。 惯例声明&#xff1a;本人没有相关的工程…

神奇的分形艺术: Mandelbrot集和Julia集

前言 这段时间看了一个关于维度的视频介绍&#xff0c;叹于其惊艳的多维几何体和分形的视觉动画效果。其实关于分形&#xff0c;已经有很成熟的分形软件和应用场景&#xff0c;可以参看目前流行的分形软件一览&#xff0c;不过没有及时更新&#xff0c;有些链接已经进不了&…

MATLAB | 分形的艺术——(Mandelbrot)曼德勃罗特集合

PART.0 Mandelbrot 介绍 “无规则的碎片” “魔鬼的聚合物” “上帝的指纹” Mandelbrot集合有着多种称谓&#xff0c;那么什么是曼德勃罗特集&#xff1f;Mandelbrot集合可以用复二次多项式&#xff1a; f c ( z ) z 2 c f_c(z)z^2c fc​(z)z2c 来表示&#xff0c;其中c是…

神奇的Python-实现曼德布洛特(Mandelbrot)集合(一行代码,matplotlib numpy,tensorflow)分别实现

神奇的Python-实现曼德布洛特(Mandelbrot)集合(一行代码&#xff0c;matplotlib numpy&#xff0c;tensorflow)分别实现 Mandelbrot图实际上是由Mandelbrot集合构成的图像。 Mandelbrot集合的定义如下&#xff1a; z n 1 z n 2 c z_{n1}z^2_nc zn1​zn2​c 其中&#xff…

曼德勃罗集(Mandelbrot Set)

先来膜拜一下大神&#xff01; 曼德勃罗(Benoit B. Mandelbrot)&#xff0c;数学家、经济学家&#xff0c;分形理论的创始人。1924年生于波兰华沙&#xff1b;1936年随全家移居法国巴黎&#xff0c;在那里经历了动荡的二战时期&#xff1b;1948年在帕萨迪纳获得航空硕士学位&am…

用matlab画Mandelbrot(曼德布罗特)图

Mandelbrot图实际上是由Mandelbrot集合构成的图像。 Mandelbrot集合的定义如下&#xff1a; zn1z2nc 其中&#xff0c;c是一个复数。加入给定一个复数 z0 &#xff0c;比如 z00 &#xff0c;那么这个递推式会生成一个序列&#xff1a; [z0,z1,z2,z3,...] 。如果这个序列收敛…

Mandelbrot 并行实现

最近要交并行计算的作业了,这周终于把作业写了个大概,这期间感觉学了不少东西,总结一下。 Mandelbrot Set 背景 前几天逛维基百科的时候看到了如下的消息:著名数学家、分形之父Benot B. Mandelbrot(中文名本华曼德博)美国时间10月15日辞世,享年85岁。 “1979年,在哈…

Mastering Qt 5 学习笔记-Mandelbrot

是一个 Mandelbrot 分形的多线程计算。 用户将看到分形&#xff0c;并能够在该窗口中平移和缩放。Mandelbrot 分形是一个处理复数 (a bi) 的数值集&#xff0c;该图像中的每个黑色像素都趋向于发散到一个无限值&#xff0c;&#xff0c;而绿色像素则有界于一个有限值。绿色像素…

Mandelbrot集合及其渲染

什么是Mandelbrot集合&#xff1f; Mandelbrot集合是在复数平面上组成分形的点的集合&#xff0c;它正是以数学家Mandelbrot命名。 Mandelbrot集合可以用复二次多项式\[ f_c(z)z^2c \] 来定义 其中c是一个复数。对于每一个c&#xff0c;从\(z 0\),开始对\(f_c(z)\)进行迭代。 …

分形之父 Mandelbrot

著名数学家&#xff0c;被誉为分形之父的Mandelbrot先生&#xff0c;美国时间10月15日在马萨诸塞州剑桥辞世&#xff0c;享年85岁。他用“美丽”改变了我们的世界观&#xff0c;他被认为是20世纪后半叶少有的影响深远而且广泛的科学伟人之一&#xff0c;1993年他获得沃尔夫物理…

Ettercap系列 II:基于命令行界面(结合driftnet截获目标机器正在浏览的图片)

相信跟着这个系列走&#xff0c;一直看到这篇文章的读者已经了解了基于图形化Ettercap的操作&#xff0c;并对Arp欺骗和Ettercap相关的术语有所了解。本篇就如何在命令行界面下操作ettercap&#xff0c;以实现与图形化界面相同的效果展开讨论。可能你会不解&#xff1a;既然我已…

无线局域网的嗅探攻击和防御——ettercap+driftnet

&#xfeff;&#xfeff; 无线局域网的嗅探攻击和防御 -----ettercapdriftnet 1 实验要求和目的 ●了解局域网转发数据的规则与协议 ●了解抓包软件的原理与操作流程 ●对网络中数据传输的协议有更深层次的认识 2 实验原理和背景知识 2.1 抓包软件与分析软件 本次嗅探试验所…

python实现图片嗅探工具——自编driftnet

python实现图片嗅探工具——自编driftnet 前言一、数据包嗅探二、图片捕获三、图片显示及主函数写在最后 前言 想必尝试过中间人攻击&#xff08;MITM)的小伙伴&#xff0c;大概率是知道driftnet的。这是一款简单使用的图片捕获工具&#xff0c;可以很方便的从网络数据包中抓取…

kali中 arpspoof、driftnet、流量转发的图片抓取

1、开启内核转发模式&#xff08;echo 1为转发 echo 0为拦截&#xff09; echo 1 /proc/sys/net/ipv4/ip_forward 配置完成使用命令查看cat /proc/sys/net/ipv4/ip_forward 2、使用 Arpspoof 开始攻击 命令:Arpspoof -i (自己网卡) -t 目标IP 网关 3、打开另一个终端 查看dri…

ARP欺骗攻击(流量图片)——dsniff与driftnet使用

ARP欺骗攻击&#xff08;流量&图片&#xff09; 原理&#xff1a; 首先我们![请添加图片描述](https://img-blog.csdnimg.cn/7de7923387224bcda1ea4be958032ae9.png 要明白何为ARP&#xff08;地址解析协议&#xff09;&#xff1a;是根据 IP地址 获取 物理地址 的一个 TC…

NO.26——利用ettercap和driftnet截获数据流里的图片

原理 Ettercap最初设计为交换网上的sniffer&#xff0c;但是随着发展&#xff0c;它获得了越来越多的功能&#xff0c;成为一款有效的、灵活的中介攻击工具。它支持主动及被动的协议解析并包含了许多网络和主机特性&#xff08;如OS指纹等&#xff09;分析。 Ettercap…

linux嗅探器抓包,Kali Linux 嗅探/欺骗工具 driftnet 教程

日期:2018年01月11日 观看: 13,491 C 次 Driftnet是一个监听网络流量并从它观察到的TCP流中提取图像的程序。有趣的是看到很多网络流量的主机上运行。在实验性增强中,driftnet现在从网络流量中挑选出MPEG音频流,并尝试播放它们。 Driftnet是一款从网络流量捕获图像并将其显…

ARP中使用driftnet工具捕获图片

在进行任何网络攻防实验时&#xff0c;请务必遵守当地法律法规以及道德准则&#xff0c;必须遵守法律规定&#xff0c;只能在合法授权的情况下进行实验和演练。 预备知识 基本网络概念&#xff1a;了解TCP/IP协议、IP地址、MAC地址等基本网络概念。 ARP协议&#xff1a;了解A…