一、解決問題
從圖中的某個頂點出發到達另一個頂點的最短路徑。
二、算法思路
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 }