赞
踩
贝尔曼-福特算法(Bellman-Ford Algorithm)是一种用于求解单源最短路径问题的算法,它可以处理带有负权边的图。 该算法的实现思路是通过不断迭代松弛操作来更新最短路径,直到找到最优解。
名词解释:
1. 松弛操作:不断更新最短路径和前驱结点的操作。
2. 负权回路:绕一圈绕回来发现到自己的距离从0变成了负数,到各结点的距离无限制的降低,停不下来
想象一下你正在一个城市中寻找最短路径。 你可以从一个路口开始,沿着道路前进,并记录下每个路口的距离。 贝尔曼-福特算法的工作方式类似:
首先,将所有路口的距离设置为无穷大,并将起点距离设置为 0。
然后,遍历所有道路,并对每个路口进行以下操作:
重复上述步骤 n - 1 次,其中 n 是路口的数量。
通过不断重复上述步骤,最终可以找到所有路口到起点的最短路径。
代码
- void ford() {
- // 初始化距离数组,表示起点到每个顶点的距离为无穷大
- for (int i = 1; i <= n; i++) {
- dis[i] = INF;
- }
- dis[1] = 0; // 起点到自身的距离为0
- // 进行n-1次松弛操作
- for (int k = 1; k <= n - 1; k++) {
- for (int i = 1; i <= m; i++) {
- // 如果通过当前边能够使终点的距离更短,则更新距离
- if (dis[v[i]] > dis[u[i]] + w[i]) {
- dis[v[i]] = dis[u[i]] + w[i];
- }
- }
- }
- }

如有不理解的可以上b站上看up主@简枫叶
Bellman算法的核心就是松驰,没有贪心策略,也使它的时间复杂度比较高。因为它是单纯的松驰。首先我们要明白的是:如果处于第n层的节点,在它上一层的即n-1层所以节点的dist已经确定为最终真实值,那么通过一次遍历,第n层节点的dist也能被确定为最终真实值。第一次迭代,获得的信息是:与源点相邻点的真正dist(第二层节点),(其他点的可能仍为无穷大,或者为松驰一次状态);第二次循环,因为第二层的信息已经完全掌握,此次迭代是能确定第三层节点(从源点出发,经过2条边)的点的真实最短距离。(由于遍历的过程中,只完全掌握了第一层,其他节点的dist不能完全确定为最终的dist);如此循环,遍历n-1次,第n层的节点已经遍历完,至此,所有节点的dist都最终确定了(解释了为啥能求最短路)
邮递员送信
题目描述
有一个邮递员要送东西,邮局在节点 1。他总共要送 n-1 样东西,其目的地分别是节点 2 到节点 n。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有 m条道路。这个邮递员每次只能带一样东西,并且运送每件物品过后必须返回邮局。求送完这 n-1 样东西并且最终回到邮局最少需要的时间。
输入格式
第一行包括两个整数,n 和 m,表示城市的节点数量和道路数量。
第二行到第 (m+1) 行,每行三个整数,u,v,w,表示从u 到 v 有一条通过时间为 w 的道路。
输出格式
输出仅一行,包含一个整数,为最少需要的时间。
- #include <stdio.h>
-
- #define INF 99999999 // 定义无穷大值
- #define MAXN 1005 // 最大顶点数
- #define MAXM 100005 // 最大边数
-
- int n, m; // 顶点数和边数
- int u[MAXM], v[MAXM], w[MAXM]; // 边的起点、终点、权值
- int dis[MAXN]; // 存储起点到各顶点的最短距离
-
- // 初始化函数,读入顶点数、边数以及每条边的起点、终点、权值
- void init() {
- scanf("%d %d", &n, &m); // 输入顶点数n和边数m
- for (int i = 1; i <= m; i++) {
- scanf("%d %d %d", &u[i], &v[i], &w[i]); // 输入每条边的起点、终点、权值
- }
- }
-
- // 反转边的起点和终点
- void over() {
- for (int i = 1; i <= m; i++) {
- int temp = u[i];
- u[i] = v[i];
- v[i] = temp;
- }
- }
-
- // Ford算法求解最短路径
- void ford() {
- // 初始化距离数组,表示起点到每个顶点的距离为无穷大
- for (int i = 1; i <= n; i++) {
- dis[i] = INF;
- }
- dis[1] = 0; // 起点到自身的距离为0
- // 进行n-1次松弛操作
- for (int k = 1; k <= n - 1; k++) {
- for (int i = 1; i <= m; i++) {
- // 如果通过当前边能够使终点的距离更短,则更新距离
- if (dis[v[i]] > dis[u[i]] + w[i]) {
- dis[v[i]] = dis[u[i]] + w[i];
- }
- }
- }
- }
-
- int main() {
- init(); // 初始化
- int ans = 0; // 记录总距离
- ford(); // 调用Ford算法计算从起点到各顶点的最短距离
- for (int i = 1; i <= n; i++) {
- ans += dis[i]; // 累加起点到各顶点的最短距离
- }
- over(); // 反转边的起点和终点
- ford(); // 重新计算最短路径
- for (int i = 1; i <= n; i++) {
- ans += dis[i]; // 累加起点到各顶点的最短距离
- }
- printf("%d\n", ans); // 输出总距离
- return 0;
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。