Bellman-Ford可以處理帶負權圖的單源最短路問題。(帶負勸環的圖,沒法求出單源最短路)java
Bellman-Ford的主要思想以下:數組
給定一張有向圖,若對於圖中的某一條邊(x,y,z),有\(dist[y]<=dist[x]+z\)成立,則稱該邊知足三角不等式。若全部邊都知足三角不等式,則dist數組就是所求最短路優化
Bellman-Ford的流程以下:spa
掃描全部的邊(x,y,z),若dist[y] > dist[x] + z , 則用dist[x] + z 更新 dist[y]code
重複上述步驟,直到沒有更新操做發生。隊列
SPFA是在上述基礎上,使用隊列進行優化,核心思想就是說:只有已經被鬆弛的點,纔可能去鬆弛其餘的點。咱們能夠經過隊列來維護已經被鬆弛的點,那麼咱們就不須要每次遍歷全部的邊了。class
/** 鏈式前向星來存圖 int e[MAX_EDGE][2],hd[MAX_N],nxt[MAX_EDGE],top; void add(int u,int v,int w){ e[++top][0]=v; e[top][1]=w; nxt[top]=hd[u]; hd[u]=top; } **/ // Bellman-Ford while(true){ bool f=false; for(int i=1;i<=n;i++) { for(int ev=hd[i];ev;ev=nxt[ev]){ int v=e[ev][0],w=e[ev][1]; if(dis[i]+w<dis[v]) { dis[v]=dis[i]+w; f=true; } } } if(f==false) break; } //SPFA queue<int>q; q.push(start); while(q.size()>0){ int u=q.front(); q.pop(); vis[u]=0; for(int ev=hd[u];ev;ev=next[ev]){ int v=e[ev][0],w=e[ev][1]; if(dis[u]+w<dis[v]){ dis[v]=dis[u]+w; if(!vis[v]) { vis[v]=1;q.push(v); } } } }
/* 題目連接:https://ac.nowcoder.com/acm/problem/14369?&headNav=www spfa的最短路的寫法 鏈式前向星 */ import java.util.*; public class Main { private static int e[][] = new int[202000][2]; private static int nxt[] = new int[220000]; private static int hd[] = new int [20020]; private static int top = 0; private static int n,m; public static void main(String[] args) { Scanner in = new Scanner(System.in); n = in.nextInt(); m = in.nextInt(); for(int i=1;i<=m;i++) { add(in.nextInt(),in.nextInt(),in.nextInt()); } int dis[] = new int[n+1]; int vis[] = new int[n+1]; Arrays.fill(dis,Integer.MAX_VALUE); dis[1]=0; //能夠按照點來遍歷,也能夠按照邊來遍歷 //只有被鬆弛的點,纔可能去鬆弛其餘的點。spfa的本質就是這個 Queue<Integer>q = new LinkedList<Integer>(); q.offer(1); while(!q.isEmpty()) { int u = q.peek(); q.poll(); vis[u] = 0; for(int i=hd[u];i>0;i=nxt[i]){ int v=e[i][0],w=e[i][1]; if(dis[u]+w < dis[v]){ dis[v] = dis[u]+w; if(vis[v] == 0) { q.offer(v); vis[v] = 1; } } } } for(int i=2;i<=n;i++) { System.out.println(dis[i]); } return; } private static void add(int u,int v,int w){ e[++top][0] = v; e[top][1] = w; nxt[top] = hd[u]; hd[u] = top; } }