SPFA

一、解决问题

从图中的某个顶点出发到达另一个顶点的最短路径。

二、算法思路

Shortest Path Faster Algorithm (SPFA)。一般认为是队列优化的贝尔曼-福特算法。是一个用于求有向带权图单源最短路径的算法,并且适用于有负权重的图。如果一个顶点被加入了超过顶点的个数,则这个图就有负环

基本思路

  • 每个节点都用于松弛其相邻节点的备选节点。
  • 维护一个备选节点队列
  • 仅有节点被松弛后才会放入队列
  • 上述流程不断重复直到队列没有节点

伪代码:

 1 function spfa(G, s):
 2     //初始化所有节点都是最大距离
 3     for each vertex != s in G:
 4         d[vertex] = inf
 5     d[s] = 0
 6     offer s into queue
 7     while(queue is not empty):
 8         u = poll queue
 9         for each v in edge(u):
10             if d[u] + w[u, v] < d[v]:
11                 d[v] = d[u] + w[u,v]
12                 if v not in queue:
13                     offer v into queue

三、图例

首先算一下最短路径为了用来验证

distance(1,5) = 8
distance(1,4) = 3
distance(1,2) = 9
distance(1,3) = 11
distance(1,6) = 12

过程

  • d[a] 为源点到a的距离
  • poll为从队列取出点
  • offer为每次放入队列的点
  • q为队列
  • 红色的为最后的结果

四、 Code (这里面的图表示形式用链式前向星更简洁一些)

 1 package algorithm;
 2 
 3 
 4 import java.util.*;
 5 
 6 public class SPFATest {
 7     private static final int INF = 0x7fffffff;
 8     private static class Edge {
 9         int source;
10         int target;
11         int weight;
12 
13         private Edge(int source, int target, int weight){
14             this.source = source;
15             this.target = target;
16             this.weight = weight;
17         }
18     }
19     public static class Graph {
20         
21 
22         int[] nodes;
23         HashMap<Integer, List<Edge>> nodeWithEdges;
24 
25         private Graph init(int[] nodes, List<Edge> edges) {
26             this.nodes = nodes;
27             nodeWithEdges = new HashMap<>();
28             for (Edge edge : edges) {
29                 List<Edge> edgeTemp = nodeWithEdges.getOrDefault(edge.source, new ArrayList<>());
30                 edgeTemp.add(edge);
31                 nodeWithEdges.put(edge.source, edgeTemp);
32             }
33             return this;
34         }
35 
36         public int[] getAllNodes() {
37             return this.nodes;
38         }
39 
40         private List<Edge> getEdgesOfNode(int node) {
41             return nodeWithEdges.get(node);
42         }
43     }
44 
45     public static int[] SPFA(int source, Graph graph) {
46         int n = graph.nodes.length;
47         int[] d = new int[n+1];
48         for (int i = 0; i <= n; i++) {
49             d[i] = INF;
50         }
51         d[source] = 0;
52         boolean[] nodeExistsInQ = new boolean[n+1];
53         Deque<Integer> deque = new ArrayDeque<>();
54         deque.offer(source);
55         nodeExistsInQ[source] = true;
56 
57         while (!deque.isEmpty()) {
58             int u = deque.poll();
59             nodeExistsInQ[u] = false;
60             if(graph.getEdgesOfNode(u) == null) continue;
61 
62             for (Edge edge : graph.getEdgesOfNode(u)) {
63                 int v = edge.target;
64                 if (d[u] + edge.weight < d[v]) {
65                     d[v] = edge.weight + d[u];
66 
67                     if(!nodeExistsInQ[v]){
68                         deque.offer(v);
69                         nodeExistsInQ[u] = true;
70                     }
71                 }
72             }
73         }
74         return d;
75     }
76 
77     public static void main(String [] args){
78         int []nodes = new int[]{1,2,3,4,5,6};
79         List<Edge> edges = new ArrayList<>();
80         edges.add(new Edge(1,2,9));
81         edges.add(new Edge(1,4,3));
82         edges.add(new Edge(1,5,13));
83         edges.add(new Edge(2,4,7));
84         edges.add(new Edge(2,3,2));
85         edges.add(new Edge(3,4,20));
86         edges.add(new Edge(3,6,1));
87         edges.add(new Edge(4,5,5));
88         edges.add(new Edge(4,6,19));
89 
90         Graph graph = new Graph().init(nodes, edges);
91 
92         int []d = SPFA(1, graph);
93         for(int i = 1; i <= nodes.length; i++){
94             System.out.println(d[i]);
95         }
96     }
97 }
原文地址:https://www.cnblogs.com/ylxn/p/12263557.html