bellman_ford算法
应用于有负权值的求最短路
思路:
进行n次迭代,每一次对边进行遍历,然后更新(松弛操作)
dist[b]=min(dist[b],dist[a]+w)dist代表了某个点距离起点的距离
也可以用此算法来判断有无负环,因为如果有负环那最小值经过不断迭代会变成无穷小
有一点点像dijkstra算法
在结束之后,一定有这样的一个关系式:
dist[b]<=dist[a]+w;(对于所有的边都满足)
dijkstra算法分为两步,第一步尤为重要就是找出未被确定的最小值的那个点
第二部就开始利用所找到的点进行更新
而bellman算法则是一次次的迭代对边进行更新
本质上操作不太一样
负环可能不存在最小路
负环不在路径中的除外
可能这么说依然会有些抽象,觉得好像两个算法差不多呀,那咱们来模拟一下:
含有负权的一个图
dijkstra算法:
把第一个一号点初始化为dist[1]=0,后面的点初始化为正无穷
由1号点出发,可以到达的边(更新)
dist[2]=2,dist[3]=5
下一步了:找到距离1号点最近的那个点的距离:(这里也就是2号点)
那2号点确定下来放入s集合中,由2号点继续更新dist[4]=dist[2]+w=4;
找到没有在集合里dist距离最小的点:dist[4]=4依然最小,然后再继续
最后走完全程会发现答案得到的是5,但明眼可见最小值是第二条路径答案是4才对,所以这个时候dijkstra算法不好用了
而bellman算法特别适合于有负权的并且走不超过k条边
(来自acwbellman算法的最高赞题解)
其实整个过程还是很像bfs的,但bfs复杂度太高就不考虑啦
为什么要进行备份:
bellman分为两步
第一步迭代
第二步枚举所有的边
就是在这个图里面,虽然说是迭代了一次,但枚举到2号点的时候,在之前被更新过了,3号点就会被2这个更小的值给覆盖会变成2,而答案是3呀(发生串联)
那如何不发生串联:
我们在更新的时候只保证使用上一次迭代的结果
所以在这里需要备份一下:
backup里面存的是上一次迭代的结果
但如果备份了呢
第一次迭代2被更新为1,而迭代之前的dist[2]是正无穷,那3用备份的结果就是正无穷+1,那还是正无穷
如果没有备份,还是在第一次迭代,3号点会被更新为2,这个就是不对的
#include<iostream> #include<cstring> using namespace std; const int N=510,M=1e5+10; int dist[N],backup[M]; struct dge{ int a,b,w; }s[M];//有m条边 int n,m,k; int bellman_ford(){ memset(dist,0x3f,sizeof(dist));//初始化 dist[1]=0; for(int i=1;i<=k;i++)//迭代k次 { memcpy(backup,dist,sizeof(dist));//在迭代之前保存一下当前的值,否则会出现串联反应 for(int j=1;j<=m;j++) { auto e=s[j]; dist[e.b]=min(dist[e.b],backup[e.a]+e.w); } } } int main(){ cin>>n>>m>>k; for(int i=1;i<=m;i++) { int a,b,c; cin>>a>>b>>c; s[i]={a,b,c}; } bellman_ford(); if(dist[n]>0x3f3f3f3f/2) cout<<"impossible"<<endl; else cout<<dist[n]<<endl; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具