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 }
谢谢!