bellman-ford 算法与 dijkstra 算法类似,都是以松弛操作作为基础。dijkstra 算法以贪心法选取未被处理的具有最小权值的节点,然后对其进行松弛操作;而 bellman-ford 算法对所有边都进行松弛操作,共 n-1 次。如果第 n 次操作仍然可以松弛,则必定存在一个负环,因为负环可以不断地减少最短路径的长度。节点数为 n,边数为 m,则 bellman-ford 算法的最长运行时间为 o(nm)。
二 算法步骤1 数据结构
因为需要利用边进行松弛,因此采用边集数组存储。每条边都有三个域:两个端点a和b,以及边权w
2 松弛操作
对所有的边 j(a,b,w),如果 dis[e[j]b]>dis[e[j].a]+e[j].w,则松弛,另 dis[e[j]b]=dis[e[j].a]+e[j].w。其中,dis[v] 表示从源点到节点 v 的最短路径长度。
3 重复松弛操作 n-1 次
4 负环判断
再执行一次松弛操作,如果仍然可以松弛,则说明右负环。
三 算法实现package graph.bellmanford; import java.util.scanner; public class bellmanford { static node e[] = new node[210]; static int dis[] = new int[110]; static int n; static int m; static int cnt = 0; static { for (int i = 0; i < e.length; i++) { e[i] = new node(); } } static void add(int a, int b, int w) { e[cnt].a = a; e[cnt].b = b; e[cnt++].w = w; } static boolean bellman_ford(int u) { // 求源点 u 到其它顶点的最短路径长度,判负环 for (int i = 0; i < dis.length; i++) { dis[i] = 0x3f; } dis[u] = 0; for (int i = 1; i < n; i++) { // 执行 n-1 次 boolean flag = false; for (int j = 0; j < m; j++) // 边数 m 或 cnt if (dis[e[j].b] > dis[e[j].a] + e[j].w) { dis[e[j].b] = dis[e[j].a] + e[j].w; flag = true; } if (!flag) return false; } for (int j = 0; j < m; j++) // 再执行 1 次,还能松弛说明有环 if (dis[e[j].b] > dis[e[j].a] + e[j].w) return true; return false; } static void print() { // 输出源点到其它节点的最短距离 system.out.println("最短距离:"); for (int i = 1; i <= n; i++) system.out.print(dis[i] + " "); system.out.println(); } public static void main(string[] args) { int a, b, w; scanner scanner = new scanner(system.in); n = scanner.nextint(); m = scanner.nextint(); for (int i = 0; i < m; i++) { a = scanner.nextint(); b = scanner.nextint(); w = scanner.nextint(); add(a, b, w); } if (bellman_ford(1)) // 判断负环 system.out.println("有负环!"); else print(); }} class node { int a; int b; int w;}
四 测试1 没有负环的测试
2 有负环的测试
以上就是java bellman-ford算法原理及实现方法的详细内容。