图论------贝尔曼-福德(Bellman-Ford)算法

算法概述:

Bellman-Ford算法核心代码如下

for(int i = 1;i<=n-1;i++)

for(int j = 1;j<=m;j++)

if(dicv\[j]> dicu\[j] + wj]

dicv\[j] = dicu\[j] + wj;

首先我们要了解一个点就是我们这次不再使用邻接矩阵来存储图的信息,而是定义三个一维数组来存储图的信息。

首先定义 un 来存储边的起点,vn来存储边的终点,wn来存储边的长(权重)。

例如存储如下元素

4 4
1 2 3
2 4 7
3 4 5
3 1 3


和Dijkstra算法一样,这段代码也是求单源最短路径,所以我们同样也要定义一个dicn数组来存储所有点到1的最短距离。注意,这里因为使用的并非邻接矩阵,所以初始化dic时默认除了dic1 = 0以外,暂时全部看作不连通,也就是假设以以上数据为例,dic内容要初始化为

【0 ,inf, inf, inf】,其中inf看作无穷大,表示不通。

那么我们再来看核心代码的最后两句。

if(dicv\[j]> dicu\[j] + wj]

dicv\[j] = dicu\[j] + wj;

dicv\[j]的值是1 到 vj这个点的值, dicu\[j] 是 1 到 uj 这个点的值 , wj 是 uj 到 vj 的值,意思是如果如果 1 通过 1 -> uj -> vj 这条路比 1 -> vj 值小的话,更新dicv\[j]的值。也就是通过uj ->vj 这条边进行松弛来优化路径。

初始化示意图如下:

for(int i = 1;i<=n-1;i++)

for(int j = 1;j<=m;j++)

if(dicv\[j]> dicu\[j] + wj]

dicv\[j] = dicu\[j] + wj;

当第一轮循环时:

当先通过 j = 1 通过第一条边进行优化时, if(dic 2 > dic 1 + 3],发现dic2 需优化,然后

重置 dic2 = dic1+3 = 3。

当 j = 2 时 通过第二条边进行优化时, if(dic 4 > dic 2 + 7],发现dic4 可以优化,然后

重置 dic 4 = dic 2 + 7 = 3+7 = 10。

当 j = 3时,通过第三条边进行优化时,if(dic 4 > dic 3 + 5],发现dic4无法优化,因为

dic 4 = 10 < dic 3 + 5 =inf + 5。

**当 j = 4 时 通过第四条边进行优化时, if(dic 1 > dic 3 + 3],**发现dic1无法优化,因为

dic 1 = 0 < dic 3 + 3 =inf + 3。

最后经过一轮松弛后得到 dic = 0, 3, inf ,10;


当 i= 2 进行第二轮松弛时,

当先通过 j = 1 通过第一条边进行优化时, if(dic 2 > dic 1 + 3],发现dic2 无需优化,因为****dic2 = dic1+3 = 3。

当 j = 2 时 通过第二条边进行优化时, if(dic 4 > dic 2 + 7],发现dic4 无需优化

当 j = 3时,通过第三条边进行优化时,if(dic 4 > dic 3 + 5],发现dic4无需优化

**当 j = 4 时 通过第四条边进行优化时, if(dic 1 > dic 3 + 3],**发现dic1无需优化

这样我们就完成了这组数据,因为这是构建的有向图,所以1 才无法到达 3.

既然很清晰流程了 我再丢给大家一组数据:

5 7
1 2 8
1 3 1
1 4 2
3 4 2
2 4 3
3 5 3
4 5 3

现在请找到一张草稿纸来试着执行刚才所讲的流程。

具体代码:

#include<stdio.h>
int main(void)
{
int u10, v10, w10;
int n, m, inf = 99999999;
int dic10 = { 0 };

scanf_s("%d%d", &n, &m);

for (int i = 1; i <= m; i++)
scanf_s("%d%d%d", &ui, &vi, &wi);****//存储边的信息

for (int i = 2; i <= n; i++)
dici = inf;****//初始化1 的单源最短路径值。

//核心代码

for (int i = 1; i <= n - 1; i++)
for (int j = 1; j <= m; j++)
if (dicv\[j] > dicu\[j] + wj)
dicv\[j] = dicu\[j] + wj;

for (int i = 1; i <= n; i++)
printf("%d ", dici);****//输出结果

}

注意事项:

最外层代码循环n-1次的原因是,n 个顶点,1到任何顶点的最多经过n-1个顶点。每一轮松弛循环如果没有完成单源最短路径的最终结果,都至少会有一次松弛。

细心的同学可能会发现我们刚才使用的数据:

5 7
1 2 8
1 3 1
1 4 2
3 4 2
2 4 3
3 5 3
4 5 3

是上一篇文章的内容,在上一篇中结果是:0 5 1 2 4 。

而在这里答案是:0 8 1 2 4。

那么为什么会造成这种影响呢,因为我们使用的这段代码是处理有向图的,而在上一篇文章中是处理无向图的,那么有没有什么办法来改进这段代码使代码能够处理无向图呢?答案当然是可以的,而且十分简单。

聪明的同学注意到数据

4 4
1 2 3
2 4 7
3 4 5
3 1 3

在第二轮就能发现没有优化证明已经得出结果,每必要进行n-1轮循环,那么大家思考下,怎么提前退出循环呢?

课后作业:

改进这段代码使代码能够处理无向图。

如何证明达到最优解提前退出循环。

明天带来答案。

相关推荐
Suxing911 小时前
C语言基础分享:从“租房”到“拆迁”,C语言动态内存管理
java·数据结构·算法
LuminousCPP11 小时前
单链表专题(四)-刷题复盘篇-LeetCode 138 随机链表复制|原地拷贝法突破复杂指针操作
数据结构·笔记·算法·leetcode·链表
逆境不可逃12 小时前
【LeetCode 912】排序数组——随机化快速排序详解
数据结构·算法·排序算法
Coder-magician12 小时前
《代码随想录》刷题打卡day31:动态规划-背包问题part02
算法·动态规划
薛定e的猫咪12 小时前
从因果视角解决多智能体协作:细读 SCIC 算法
算法
c2385612 小时前
《算法武林谱:四大排序神功与二分寻宝术全解》
数据结构·算法·排序算法
一米阳光866112 小时前
软考(中级)软件设计师核心笔记(9)算法——时间复杂度与空间复杂度、查找算法、排序算法
笔记·算法·职场发展·软考·软件设计师·中级职称
OpenApi.cc12 小时前
MoCode — AI Agent Server (Docker) + macOS Desktop Client(开源项目)
数据结构·人工智能·深度学习·神经网络
Mem0rin12 小时前
二分查找:左右边界
数据结构·算法
lazily-c13 小时前
数据结构模板
数据结构