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; } }