我们在之前介绍了bellman-ford算法求解带负权的最短路问题,也解释了为什么我们不能使用dijkstra算法进行求解,今天我们要介绍一种新的求解带负权最短路问题的方法,spfa算法,这其实也是对bellman-ford算法优化。
spfa算法在最好的情况下,算法时间复杂度为O(m),最坏情况下算法时间复杂度为O(nm)
那么spfa是如何对bellman-ford算法进行优化的呢?
在bellman-ford算法的松弛操作中,即使点b并没有被更新,还是需要用它去更新其他节点,这其实是没有必要的,因为最短路要想变得更短,肯定是其中有一段距离变得更短了,才会需要更新,如果我们没有变化,去更新其他节点也是徒劳的。
所以spfa对此处进行了优化,只将距离变短了的点加入队列中来更新最短距离
如题所示:
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数。
请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 impossible。
数据保证不存在负权回路。
输入格式
第一行包含整数 n 和 m。
接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。
输出格式
输出一个整数,表示 1 号点到 n 号点的最短距离。
如果路径不存在,则输出 impossible。
数据范围
1≤n,m≤105,
图中涉及边长绝对值均不超过 10000。
输入样例:
3 3
1 2 5
2 3 -3
1 3 4
输出样例:
2
代码如下:
import java.io.*;
import java.util.*;
public class Main{
public static int[] e = new int[100010];
public static int[] ne = new int[100010];
public static int[] w = new int[100010];
public static int[] h = new int[100010];
public static int[] d = new int[100010];
public static boolean[] st = new boolean[100010]; // 表示节点是否在队列中,在队列中就只需要更新距离就行了,不用重复入队
public static int idx = 0;
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] lens = br.readLine().split(" ");
int n = Integer.parseInt(lens[0]);
int m = Integer.parseInt(lens[1]);
Arrays.fill(h, -1);
while(m-- > 0){
String[] res = br.readLine().split(" ");
int a = Integer.parseInt(res[0]);
int b = Integer.parseInt(res[1]);
int c = Integer.parseInt(res[2]);
add(a, b, c);
}
int t = spfa(n);
if (t == -1) System.out.print("impossible");
else System.out.print(t);
}
public static void add(int a, int b, int c){
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
public static int spfa(int n){
Queue<Integer> q = new LinkedList<>();
q.offer(1);
Arrays.fill(d, 0x3f3f3f3f);
d[1] = 0;
while(!q.isEmpty()){
int t = q.poll();
st[t] = false;
for (int i = h[t]; i != -1; i = ne[i]){
int j = e[i];
if(d[j] > d[t] + w[i]){
d[j] = d[t] + w[i];
if(!st[j]){
st[j] = true;
q.offer(j);
}
}
}
}
if (d[n] == 0x3f3f3f3f) return -1;
else return d[n];
}
}