算法/最短路径/Bellman-Ford贝尔曼福特算法
来源:互联网 发布:大学生淘宝兼职 编辑:程序博客网 时间:2024/05/16 02:06
问题描述
Dijkstra算法是处理单源最短路径的有效算法,但它局限于边的权值非负的情况,若图中出现权值为负的边,Dijkstra算法就会失效,求出的最短路径就可能是错的。这时候,就需要使用其他的算法来求解最短路径,Bellman-Ford算法就是其中最常用的一个。该算法由美国数学家理查德•贝尔曼 (Richard Bellman, 动态规划的提出者) 和小莱斯特•福特 (Lester Ford) 发明。
算法分析
首先介绍一下松弛计算:
松弛计算之前如图(a),点B的值是8,但是点A的值加上边上的权重2,得到5,比点B的值小,所以,点B的值减小为5。这个过程的意义是,找到了一条通向B点更短的路线,且该路线是先经过点A,然后通过权重为2的边,到达点B。
如果出现情况(b)则不会修改B的值,因为3+6>8。
- 给定图G(V, E) (其中V、E (Edge) 分别为图G的顶点集与边集),源点s,数组 d(i) (Distant) 记录从源点 s 到顶点 i 的路径长度,初始化 d(n)=∞ 表示不可达,d(s)=0;
- 执行循环,在循环内部,遍历所有的边,进行松弛计算:
- 对于每一条边e(u, v),如果 d(u)+w(u, v) < d(v),则令d(v)=d(u)+w(u, v),w(u, v) 为边 e(u,v) 的权值;
- 若上述操作没有对 d 进行更新,说明最短路径已经查找完毕或者部分点不可达,跳出循环。否则执行下次循环;
- 遍历途中所有的边 e(u, v),判断是否存在 d(u)+w(u, v) < d(v) 的情况,如果有返回false,否则数组 d(n) 中记录的就是源点s到各顶点的最短路径长度。
之所以需要第三部分,是因为如果存在从源点可达的权为负的回路,则应为无法收敛而导致不能求出最短路径。考虑下面过程,图中存在一条负回路:
经过第一次遍历后如图(b),B的值变为5,C变为8,注意权重为-10的边,它的存在导致A的值变为-2,此时A到B的边有5>5+(-2)。
我之前有一个疑问,为什么情况三说明有一条负回路,而不是有一条负边,现在解决了:C的值8来着5+3,如果CA边的绝对值<8,那么A的值仍为0。假设为CA=-3,因为8+(-3)=5>0(A),所以不会改变A,写出来似乎有点蠢的样子…
第二次遍历后如图(c),B的值变为3,C变为6,A变为-4。正是因为有一条负边在回路中,导致每次遍历后,各个点的值不断变小,因此无法收敛。
因为第二部分循环的次数是定长的,而且正常情况下能保证d(v)<=d(u)+w(u, v),所以如果存在无法收敛的情况,则肯定能够在第三部分中检查出来。
代码如下:
import java.util.Scanner;public class BellmanFord { private int[] distant; private Edge[] edge; class Edge { int u;//边的起点 int v;//边的终点 int weight;//边的权重 Edge(int u, int v, int weight) { this.u = u; this.v = v; this.weight = weight; } } private void relax(int u, int v, int weight) { if (distant[v] > distant[u] + weight) { distant[v] = distant[u] + weight; } } private void bellmanFord(int nodeNum) { distant = new int[nodeNum]; // 初始化源点到其它顶点之间的距离为无穷大 for (int i = 1; i < nodeNum; i++) { distant[i] = Integer.MAX_VALUE; } // 进行(nodeNum - 1)次遍历 for (int i = 1; i < nodeNum; i++) { //每一个点 for (Edge anEdge : edge) { //每一条边 relax(anEdge.u, anEdge.v, anEdge.weight); } } // 判断是否有负回路 boolean flag = true; for (Edge anEdge : edge) { if (distant[anEdge.u] > distant[anEdge.v] + anEdge.weight) { flag = false; break; } } // 打印结果 if (flag) { for (int i = 0; i < nodeNum; i ++) { System.out.print(distant[i] + " "); } } else { System.out.println("存在负回路,没有最短距离"); } } public static void main(String[] args) { BellmanFord b = new BellmanFord(); Scanner in = new Scanner(System.in); System.out.println("请输入一个图的顶点总数n和边总数p:"); int nodeNum = in.nextInt(); int edgeNum = in.nextInt(); b.edge = new Edge[edgeNum]; System.out.println("请输入具体边的数据:"); for (int i = 0; i < edgeNum; i++) { int u = in.nextInt(); int v = in.nextInt(); int weight = in.nextInt(); b.edge[i] = b.new Edge(u, v, weight); } b.bellmanFord(nodeNum); }}
- 算法/最短路径/Bellman-Ford贝尔曼福特算法
- 最短路径算法—Bellman-Ford(贝尔曼-福特)算法分析与实现(C/C++)
- 最短路径算法—Bellman-Ford(贝尔曼-福特)算法分析与实现(C/C++)
- 最短路径算法—Bellman-Ford(贝尔曼-福特)算法分析与实现(C/C++)
- 最短路径算法—Bellman-Ford(贝尔曼-福特)算法分析与实现(C/C++)
- 最短路径算法—Bellman-Ford(贝尔曼-福特)算法分析与实现(C/C++)
- 最短路径算法—Bellman-Ford(贝尔曼-福特)算法分析与实现(C/C++)
- 最短路径算法(2)—Bellman-Ford(贝尔曼-福特)算法
- 最短路径算法—Bellman-Ford(贝尔曼-福特)算法分析与实现(C/C++)
- java实现图的最短路径(SP)的贝尔曼福特(Bellman-Ford)算法
- 总结一下最短路径的贝尔曼-福特算法(Bellman-Ford)及用队列优化(spfa)
- 总结一下最短路径的贝尔曼-福特算法(Bellman-Ford)及用队列优化(spfa)
- 最短路径算法—Bellman-Ford(贝尔曼…
- Bellman-Ford(贝尔曼-福特)算法求单源最短路径
- Bellman-Ford贝尔曼福特算法实现
- 最短路径 Floyd算法 Dijkstra算法 Bellman-Ford(贝尔曼)算法
- 最短路径[Floyd算法,Dijkstra算法,Bellman-Ford(贝尔曼)]算法
- Bellman-ford(贝尔曼-福特算法)解析
- mvc 基于basecontroller、ActionFilterAttribute及路由的访问登录验证
- ECS的简单使用(windows系统)
- html中使用段落
- Java反射机制详解
- html不换行显示
- 算法/最短路径/Bellman-Ford贝尔曼福特算法
- C++实验5
- Github全面详解-16Team小组
- 服务的基本用法-2
- h5学习笔记:vue 和 数据模拟
- html文字换行显示
- 最新破解版多多返利8.3源码分享
- html保留原始排版效果
- POJ1745Divisibility