Bellman-Ford

Bellman-Ford

  • 本质:DP,对边进行操作
  • 特点:单源最短路,求解一个源点到其他所有点的最短距离
  • 适用对象:小图,允许负权有向图,不能处理负权无向图和和负环图(负环:图上边权之和为负的环)
  • 存储结构:直接存边
  • 核心思想:每轮中反复松弛所有边,若该边使距离更优则更新。最多进行 V − 1 V-1 V1轮,若之后还有边在更新,说明存在负环。
  • 算法流程:闫氏DP分析法
    • 状态表示:
      • 集合:定义源点 s s s到每个顶点的最短路长度 d i s dis dis(初始化为 + ∞ +\infty +表示该点不可达,源点初始化为0),路径数组 p a t h path path(存储其上一个来源顶点,初始化为 − 1 -1 1表示无路径)
      • 属性: M i n Min Min
    • 状态计算:设当前边为 < u , v > <u,v> <u,v>,循环执行下列步骤,直到没有结点的 d i s dis dis再更新或循环 V − 1 V-1 V1轮(若 V − 1 V-1 V1轮后还在更新说明存在负环)
      • 不选第 k k k条边:若选当前边不能使边的终点 v v v到源点 s s s的距离减小,则不选该边。 d i s [ v ] dis[v] dis[v]不变。
      • 选第 k k k条边:若选当前边能够使边的终点 v v v到源点 s s s的距离减小,则选该边。 d i s [ v ] = d i s [ u ] + w dis[v]=dis[u]+w dis[v]=dis[u]+w。(该边被松弛)
    • 状态转移方程式: d i s [ v ] = m i n ( d i s [ v ] , d i s [ u ] + w ) dis[v]=min(dis[v],dis[u]+w) dis[v]=min(dis[v],dis[u]+w)
      实际上,此处默认运用了滚动数组压到了一维。
  • 复杂度: O ( V E ) O(VE) O(VE)
  • 与Dijkstra算法的区别:
    1. Dijkstra每次考查的是先前未被考察且 d i s dis dis最小的点,一旦被考查后其将不再被考查,因此不能处理负权图
    2. Bellman-Ford每次都直接对所有边进行遍历,每轮循环中所有顶点的 d i s dis dis都有可能被修改,且最坏情形下到 V − 1 V-1 V1轮才确定,因此可适用于负权图
  • Bellman-Ford的队列优化:SPFA

C++实现

int n,m,s;//点数 边数 源点
struct edge{
	int f,t,w;
}e[MAXE];
void bellman(){
    vector<int>dis(MAXV,INF),path(MAXV,-1);
    dis[s]=0;
	for(int k=0;k<n-1;k++)//进行V-1次循环
		for(int i=0;i<m;i++)//遍历所有边
            ll U=e[i].f,V=e[i].t,W=e[i].w;
			if(dis[U]!=INF&&W!=INF&&dis[V]>dis[U]+W){
                //松弛条件:源点dis非无穷,边权值非无穷,源点中转使终点距离更近
				dis[V]=dis[U]+W;
				path[V]=U;
			}
}

路径输出

void print(int s,int t){
    if(s==t){cout<<s<<' ';return;}
    print(s,path[t]);
    cout<<t<<' ';
}

判断负环

在循环结束后,加入判断是否有边 < u , v > <u,v> <u,v>满足 d i s [ v ] > d i s [ u ] + w dis[v]>dis[u]+w dis[v]>dis[u]+w,若有则表明还可继续松弛,存在负环。

bool check(){
    for(int i=0;i<m;i++)
    	if(dis[e[i].t]>dis[e[i].f]+e[i].w) //若是非连通图,需再加条件dis[e[i].t]!=INF
            return 1;
    return 0;
}

负环还可用SPFA进行判断。

posted @   椰萝Yerosius  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示