標籤:組隊 article images url while lis 複雜 距離 輸入
目錄
1 問題描述
2 解決方案
2.1 具體編碼
1 問題描述
何為spfa(Shortest Path Faster Algorithm)演算法?
spfa演算法功能:給定一個加權連通圖,選取一個頂點,稱為起點,求取起點到其它所有頂點之間的最短距離,其顯著特點是可以求含負權圖的單源最短路徑,且效率較高。(PS:引用自百度百科:spfa是求單源最短路徑的一種演算法,它還有一個重要的功能是判負環(在差分約束系統中會得以體現),在Bellman-ford演算法的基礎上加上一個隊列最佳化,減少了冗餘的鬆弛操作,是一種高效的最短路演算法。)
spfa演算法思想:spfa就是BellmanFord的一種實現方式,其具體不同在於,對於處理鬆弛操作時,採用了隊列(先進先出方式)操作,從而大大提高了時間複雜度。 (PS:對於BellmanFord演算法可以參考本人的另一篇文章演算法筆記_070:BellmanFord演算法簡單介紹(Java))
2 解決方案
2.1 具體編碼
spfa演算法尋找單源最短路徑的時間複雜度為O(m*E)。(其中m為所有頂點進隊的平均次數,可以證明m一般小於等於2*圖頂點個數,E為給定圖的邊集合)
首先看下代碼中所使用的連通圖(PS:改圖為無向連通圖,所以每兩個頂點之間均有兩條邊):
現在求取中頂點B到其它所有頂點之間的最短距離。
具體代碼如下:
package com.liuzhen.chapter9;import java.util.ArrayList;import java.util.Scanner;public class Spfa { public long[] result; //用於得到第s個頂點到其它頂點之間的最短距離 //內部類,用於存放圖的具體邊資料 class edge { public int a; //邊的起點 public int b; //邊的終點 public int value; //邊的權值 edge(int a, int b, int value) { this.a = a; this.b = b; this.value = value; } } /* * 參數n:給定圖的頂點個數 * 參數s:求取第s個頂點到其它所有頂點之間的最短距離 * 參數edge:給定圖的具體邊 * 函數功能:如果給定圖不含負權迴路,則可以得到最終結果,如果含有負權迴路,則不能得到最終結果 */ public boolean getShortestPaths(int n, int s, edge[] A) { ArrayList<Integer> list = new ArrayList<Integer>(); result = new long[n]; boolean[] used = new boolean[n]; int[] num = new int[n]; for(int i = 0;i < n;i++) { result[i] = Integer.MAX_VALUE; used[i] = false; } result[s] = 0; //第s個頂點到自身距離為0 used[s] = true; //表示第s個頂點進入數組隊 num[s] = 1; //表示第s個頂點已被遍曆一次 list.add(s); //第s個頂點入隊 while(list.size() != 0) { int a = list.get(0); //擷取數組隊中第一個元素 list.remove(0); //刪除數組隊中第一個元素 for(int i = 0;i < A.length;i++) { //當list數組隊的第一個元素等於邊A[i]的起點時 if(a == A[i].a && result[A[i].b] > result[A[i].a] + A[i].value) { result[A[i].b] = result[A[i].a] + A[i].value; if(!used[A[i].b]) { list.add(A[i].b); num[A[i].b]++; if(num[A[i].b] > n) return false; used[A[i].b] = true; //表示邊A[i]的終點b已進入數組隊 } } } used[a] = false; //頂點a出數組對 } return true; } public static void main(String[] args) { Spfa test = new Spfa(); Scanner in = new Scanner(System.in); System.out.println("請輸入一個圖的頂點總數n起點下標s和邊總數p:"); int n = in.nextInt(); int s = in.nextInt(); int p = in.nextInt(); edge[] A = new edge[p]; System.out.println("請輸入具體邊的資料:"); for(int i = 0;i < p;i++) { int a = in.nextInt(); int b = in.nextInt(); int value = in.nextInt(); A[i] = test.new edge(a, b, value); } if(test.getShortestPaths(n, s, A)) { for(int i = 0;i < test.result.length;i++) System.out.print(test.result[i]+" "); } else System.out.println("給定圖存在負環,沒有最短距離"); }}
運行結果:
請輸入一個圖的頂點總數n起點下標s和邊總數p:6 1 18請輸入具體邊的資料:0 1 60 2 31 2 21 3 52 3 32 4 43 4 23 5 34 5 51 0 62 0 32 1 23 1 53 2 34 2 44 3 25 3 35 4 55 0 2 5 6 8
參考資料:
1. SPFA演算法詳解
演算法筆記_071:SPFA演算法簡單介紹(Java)