zl程序教程

您现在的位置是:首页 >  其他

当前栏目

最短路问题之Bellman-ford算法

2023-03-14 09:44:36 时间

题目:

  最短路:给定两个顶点,在以这两个点为起点和终点的路径中,边的权值和最小的路径。考虑权值为点之间的距离。

  单源最短路问题,Bellman-ford算法

  思路:每次循环检查所有边,可优化。

  应用于旅游等路径最小问题。

代码:

 1 import java.util.Arrays;
 2 
 3 public class 图的最短路问题_单源 {
 4     public static void main(String[] args) {
 5         int[] shortestPath = shortestPath(0);
 6         System.out.println(Arrays.toString(shortestPath));
 7         // 输出[0, 2, 5, 7, 11, 8, 16]
 8     }
 9 
10     /**
11      * 求起点到各顶点的最短距离
12      * 
13      * @param s 起点
14      * @return
15      */
16     private static int[] shortestPath(int s) {
17         int n = graph.length;
18         // 记录s到各顶点的最短距离
19         int[] d = new int[n];
20         for (int i = 0; i < n; i++) {
21             d[i] = Integer.MAX_VALUE;
22         }
23         d[s] = 0;// 到自己的距离为0
24         while (true) {
25             boolean update = false;
26             // 扫描所有的边
27             for (int i = 0; i < n; i++) {
28                 // 起点到i的最短距离还没算出来
29                 if (d[i] == Integer.MAX_VALUE)
30                     continue;
31                 for (int j = 0; j < n; j++) {
32                     int cost = graph[i][j]; // i,j之间的距离
33                     if (cost > 0) { // i,j 两点之间有边,起点是i
34                         if (d[j] > d[i] + cost) { // 起点先到i,i->j
35                                                     // 两端距离加起来比起点直接到j的距离短,则更新
36                             update = true;
37                             d[j] = d[i] + cost;
38                         }
39                     }
40                 }
41             }
42             // 无需任何更新,退出外循环
43             if (!update)
44                 break;
45         }
46         return d;
47     }
48 
49     static int[][] graph = { 
50             { 0, 2, 5, 0, 0, 0, 0 }, 
51             { 2, 0, 4, 6, 10, 0, 0 }, 
52             { 5, 4, 0, 2, 0, 0, 0 },
53             { 0, 6, 2, 0, 0, 1, 0 }, 
54             { 0, 10, 0, 0, 0, 3, 5 }, 
55             { 0, 0, 0, 1, 3, 0, 9 }, 
56             { 0, 0, 0, 0, 5, 9, 0 } 
57             };
58 }

   对于上一个代码。可以先把边集提取出来,这样不用每次扫描二维数组。

   Edge类:

 1 /**
 2  * 边 的封装
 3  * 边集可以用来表示图
 4  */
 5 public class Edge<T> implements Comparable<Edge>  {
 6     private T start;
 7       private T end;
 8       private int distance;
 9 
10       public Edge(T start, T end, int distance) {
11         this.start = start;
12         this.end = end;
13         this.distance = distance;
14       }
15 
16       public T getStart() {
17         return start;
18       }
19 
20       public void setStart(T start) {
21         this.start = start;
22       }
23 
24       public T getEnd() {
25         return end;
26       }
27 
28       public void setEnd(T end) {
29         this.end = end;
30       }
31 
32       public int getDistance() {
33         return distance;
34       }
35 
36       public void setDistance(int distance) {
37         this.distance = distance;
38       }
39 
40       @Override
41       public String toString() {
42         return start + "->" + end + ":" + distance;
43       }
44 
45       @Override
46       public int compareTo(Edge obj) {
47         int targetDis = obj.getDistance();
48         return distance > targetDis ? 1 : (distance == targetDis ? 0 : -1);
49       }
50 }
View Code

  优化过后的代码:

 1 import java.util.ArrayList;
 2 import java.util.Arrays;
 3 import java.util.List;
 4 
 5 public class 图的最短路问题_优化_边集 {
 6     public static void main(String[] args) {
 7         edges = buildEdges(graph);
 8         int[] shortestPath = shortestPath(0);
 9         System.out.println(Arrays.toString(shortestPath));
10         // 输出[0, 2, 5, 7, 11, 8, 16]
11     }
12 
13     /**
14      * 求起点到各顶点的最短距离
15      * 
16      * @param s
17      *            起点
18      * @return
19      */
20     private static int[] shortestPath(int s) {
21         int n = graph.length;
22         // 记录s到各顶点的最短距离
23         int[] d = new int[n];
24         for (int i = 0; i < n; i++) {
25             d[i] = Integer.MAX_VALUE;
26         }
27         d[s] = 0;// 到自己的距离为0
28         while (true) {
29             boolean update = false;
30 
31             for (Edge<Integer> e : edges) {
32                 if (d[e.getStart()] != Integer.MAX_VALUE && d[e.getEnd()] > d[e.getStart()] + e.getDistance()) {
33                     update = true;
34                     d[e.getEnd()] = d[e.getStart()] + e.getDistance();
35                 }
36             }
37 
38             if (!update)
39                 break;
40         }
41         return d;
42     }
43 
44     static List<Edge<Integer>> edges;
45 
46     static List<Edge<Integer>> buildEdges(int[][] graph) {
47         int n = graph.length;
48         List<Edge<Integer>> edges = new ArrayList<>();
49         for (int i = 0; i < n; i++) {
50             for (int j = 0; j < n; j++) {
51                 int cost = graph[i][j]; // i,j之间的距离
52                 if (cost > 0) { // i,j 两点之间有边,起点是i
53                     edges.add(new Edge<>(i, j, cost));
54                 }
55             }
56         }
57         return edges;
58     }
59 
60     static int[][] graph = { 
61             { 0, 2, 5, 0, 0, 0, 0 },
62             { 2, 0, 4, 6, 10, 0, 0 }, 
63             { 5, 4, 0, 2, 0, 0, 0 },
64             { 0, 6, 2, 0, 0, 1, 0 }, 
65             { 0, 10, 0, 0, 0, 3, 5 }, 
66             { 0, 0, 0, 1, 3, 0, 9 }, 
67             { 0, 0, 0, 0, 5, 9, 0 } 
68             };
69 }
View Code