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;
}
复制代码

 

posted @   小志61314  阅读(234)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示