天天看點

SPFA單源最短路算法SPFA單源最短路算法

SPFA單源最短路算法

适用情況

與 Dijkstra 算法類似,隻不過該算法可以判斷是否存在負環(不能處理負環)。目的是求單源最短路。

時間複雜度為 O(nm)

該算法可由 Dijkstra 算法替換使用,優于其在于可判斷負環。

思想

Bellman-Ford 的改進版。(下述代碼采用領接表存儲資料)

①【初始化(隊列、标記數組等)】建立一個隊列,将源點加入隊列中并做相關處理(加标記、統計入隊次數),然後循環直到隊列為空。

②【周遊相鄰點并更新資料】循環中,每次取隊首頂點(做标記),然後周遊與之相鄰的所有點。比較 此隊首頂點到源點的距離加上其相鄰點之間的距離(即為隊首頂點到源點距離+隊首頂點到與之相鄰點的距離和) 和 相鄰點到源點的距離(即源點到與之相鄰點的原始值)大小,更新相鄰點到源點的距離使之最小。

③【入隊并判負環】找到可以更新後,如果沒有标記此點則标記再入隊,并統計入隊次數(如果入隊次數大于等于 n 時則表示存在負環)

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {

	static class edge{
		int to,v,nex;
	}
	static int M = 200005;
	static int N = 20005;
	static int cnt = 0;
	static edge[] e = new edge[M];
	
	static int n, m;
	static int[] h = new int[N];//父節點集
	static int[] dis = new int[N];//源點到i的距離
	static boolean[] f = new boolean[N];//标記是否入隊
	static int[] k = new int[N];//入隊次數
	
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		
		n = cin.nextInt();//頂點數
		m = cin.nextInt();//邊數
		// a 到 b 的距離為 c
		for(int i=0;i<m;i++) {
			int a = cin.nextInt();
			int b = cin.nextInt();
			int c = cin.nextInt();
			add(a,b,c);//此為有向圖
		}
		SPFA(1);
		for(int i=2;i<=n;i++) {
			System.out.println(dis[i]);
		}
	}

	private static void SPFA(int s) {
		Queue<Integer> q = new LinkedList<>();
		Arrays.fill(dis, Integer.MAX_VALUE);
		Arrays.fill(f, false);
		Arrays.fill(k, 0);
		
		q.add(s);
		dis[s] = 0;
		f[s] = true;
		while(!q.isEmpty()) {
			int t = q.poll();
			f[t] = false;
			
			for(int i=h[t]; ;i=e[i].nex) {
				if(e[i] == null)break;
				
				int temp = e[i].to;
				if(dis[temp] > dis[t] + e[i].v) {
					dis[temp] = dis[t] + e[i].v;
					
					if(f[temp] == false) {
						q.add(temp);
						f[temp] = true;
						if(++k[temp] >= n) {//判斷是否存在負環
							System.out.println("存在負環");
							return ;
						}
					}
				}
			}
		}
	}

	private static void add(int a, int b, int c) {
		e[++cnt] = new edge();// cnt從1開始(點編号)
		e[cnt].to = b;
		e[cnt].v = c;
		e[cnt].nex = h[a];
		h[a] = cnt;
	}
}
           

如有錯誤或不合理的地方,敬請指正~

加油!!