单源最短路算法

单源最短路算法

最短路算法

朴素 Dijkstra

适用于稠密正权图,$O(N^2)$

public class SimpleDijkstra {
  final static int N = 100010, INF = Integer.paraseInt("3f3f3f3f", 16);
  final static int[] dist = new int[N];
  final static int[][] g = new int[N][N];
  final static boolean[] st = new Boolean[N];
  
  private static int simpleDijkstra(int n) {
    dist[1] = 0;
    for (int i = 0; i < n; i++) {
      int t = -1;
      for (int j = 1; j <= n; j++) {
        if (!st[j] && (t == -1 || dist[j] > dist[t])) {
          i = j;
        }
      }
      st[i] = true;
      for (int j = 1; j <= n; j++) {
        dist[j] = Math.min(dist[j], dist[t] + g[i][j]);
      }
    }
    return dist[n] == INF ? -1 : dist[n];
  }
  
  public static void main(String[] args) {
    Scanner cin = new Scanner(System.in);
    int n = cin.nextInt(), m = cin.nextInt();
    
    for (int i = 0; i < n; i++) {
      Arrays.fill(g[i], INF);
    }
    
    while (m-- > 0) {
      int a = cin.nextInt(), b = cin.nextInt(), c = cin.nextInt();
      g[a][b] = Math.min(g[a][b], c);
    }
    
    System.out.println(simpleDijkstra(n));
  }
}

堆优化 Dijkstra

适用于稀疏正权图,$O(MlogN)$

public class HeapDijkstra {
  final static int N = 100010, INF = Integer.paraseInt("3f3f3f3f", 16);
  static int idx = 0;
  final static int[] h = new int[N], e = new int[N], ne = new int[N], w = new int[N], dist = new int[N];
  final static boolean[] st = new Boolean[N];
  
  private static int simpleDijkstra(int n) {
    dist[1] = 0;
    PreorityQueue<PII> heap = new PreorityQueue<>(Comparator.comparingInt(o -> o.first));
    heap.push(new PII(0, 1));
    
    while (heap.size() > 0) {
      PII t = heap.poll();
      int ver = t.second, distance = t.first;
      
      if (st[ver]) continue;
      
      for (int i = h[ver]; i != -1; i = ne[i]) {
        int j = e[i];
        if (dist[j] > distance + w[i]) {
          dist[j] = distance + w[i];
          heap.add(new PII(dist[j], j));
        }
      }
    }
    
  	return dist[n] == INF ? -1 : dist[n];
  }
  
  public static void main(String[] args) {
    Scanner cin = new Scanner(System.in);
    Arrays.fill(h, -1);
    int n = cin.nextInt(), m = cin.nextInt();
    
    while (m-- > 0) {
      int a = cin.nextInt(), b = cin.nextInt(), c = cin.nextInt();
      e[idx] = b; w[idx] = c; ne[idx] = h[a]; h[a] = idx++;
    }
    
    System.out.println(heapDijkstra(n));
  }
}

Bellman-Ford

适用于限制边的条数,$O(NM)$

public class BellmanFord {
  final static int N = 510, M = 10010, INF = Integer.parseInt("3f3f3f3f", 16);
  final static int[] dist = new int[N], backup = new int[N];
  final static Edge[] edges = new Edge[N];
  
  private static void bellmanFord(int n, int m, int k) {
    dist[1] = 0;
    for (int i = 0; i < k; i++) {
      System.arraycopy(dist, 0, backup, 0, dist.length);
      for (int j = 0; j <= m; j++) {
        int a = edges[j].a, b = edges[j].b, w = edges[j].w;
        dist[b] = Math.min(dist[b], backup[a] + w);
      }
    }
    return dist[n] > INF >> 1 ? -1 : dist[n];
  }
  
  public static void main(String[] args) {
    Scanner cin = new Scanner(System.in);
    Arrays.fill(dist, INF);
    int n = cin.nextInt(), m = cin.nextInt(), k = cin.nextInt();

    for (int i = 0; i < n; i++) {
      int a = cin.nextInt(), b =cin.nextInt(), w = cin.nextInt();
      edges[i] = new Edge(a, b, w);
    }

    int t = bellmanFord(n, m, k);
    if (t == -1) System.out.println("Impossible");
    else System.out.println(t);
  }
}

class Edge {
  int a, b, w;
  
  public Edge(int a, int b, int w) {
    this.a = a; 
    this.b = b;
    this.c = w;
  }
}

SPFA

绝大部分情况下优于 Bellman-Ford 算法,有时也可以用于求正权图的最短路径,$O(NlogM)$

public class SPFA {
  final static int N = 10010, INF = Integer.paraseInt("3f3f3f3f", 16);
  static int idx = 0;
  final static int[] h = new int[N], ne = new int[N], e = new int[N], w = new int[N], dist = new int[N];
  final static boolean[] st = new boolean[N];
  
  private static int spfa(int n) {
    dist[1] = 0;
    Queue<Integer> q = new ArrayDeque<>();
    q.add(1);
    st[1] = true;
    
    while (q.size() > 0) {
      int t = q.poll();
      st[t] = false;
      for (int i = h[t]; i != -1; i = ne[i]) {
        int j = ne[i];
        dist[j] = Math.min(dist[j], dist[t] + w[i]);
        if (!st[j]) {
          q.add(j);
          st[j] = true;
        }
      }
    }
    return dist[n] == INF ? -1 : dist[n];
  }
}