当前位置: 首页 > ops >正文

算法模板(Java版)_图的最短路径

@ZZHow(ZZHow1024)

图的最短路径问题:

  • 单源最短路
    • 所有边权都是正数
      • 朴素 Dijkstra 算法 O(n2)O(n ^ 2)O(n2)
      • 堆优化版 Dijkstra 算法 O(m∗log2n)O(m*log_2 n)O(mlog2n)
    • 存在负权边
      • Bellman-Ford 算法 O(n∗m)O(n * m)O(nm)
      • SPFA 算法 一般O(m),最坏O(n∗m)一般 O(m),最坏 O(n * m)一般O(m),最坏O(nm)
  • 多源汇最短路
    • Floyd 算法 O(n3)O(n ^ 3)O(n3)

朴素 Dijkstra

迪杰斯特拉算法采用的是一种贪心的策略。进行 n 次迭代去确定每个点到起点的最小值,最后输出的终点的即为我们要找的最短路的距离。

  • 例题:AcWing 849. Dijkstra求最短路 I
import java.util.Scanner;public class Main {static final int N = 510;static long[][] g = new long[N][N];static long[] dist = new long[N];static boolean[] st = new boolean[N];public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int m = scanner.nextInt();for (int i = 0; i <= n; i++)for (int j = 0; j <= n; j++)g[i][j] = Integer.MAX_VALUE;while (m-- != 0) {int a = scanner.nextInt();int b = scanner.nextInt();int c = scanner.nextInt();g[a][b] = Math.min(g[a][b], c);}System.out.println(dijkstra(n));}public static long dijkstra(int n) {for (int i = 0; i <= n; i++)dist[i] = Integer.MAX_VALUE;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[t] > dist[j]))t = j;st[t] = true;for (int j = 1; j <= n; j++)dist[j] = Math.min(dist[j], dist[t] + g[t][j]);}if (dist[n] == Integer.MAX_VALUE)return -1;elsereturn dist[n];}
}

堆优化版 Dijkstra

对朴素版 Dijkstra 进行优化,在时间复杂度最高的寻找距离最短的点 O(n2)O(n^2)O(n2) 时可以使用小根堆优化,Java 语言可使用优先队列(PriorityQueue),配合自定义的 Pair 类实现。

  • 例题:AcWing 850. Dijkstra求最短路 II
import java.util.*;public class Main {static final int N = 1000010;static int idx = 0;static int[] h = new int[N];static int[] e = new int[N];static int[] w = new int[N];static int[] ne = new int[N];static long[] dist = new long[N];static boolean[] st = new boolean[N];public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int m = scanner.nextInt();Arrays.fill(h, -1);while (m-- != 0) {int a = scanner.nextInt();int b = scanner.nextInt();int c = scanner.nextInt();add(a, b, c);}System.out.println(dijkstra(n));}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 long dijkstra(int n) {Arrays.fill(dist, Integer.MAX_VALUE);dist[1] = 0;Queue<Pair> heap = new PriorityQueue<>();heap.add(new Pair(0L, 1));while (!heap.isEmpty()) {Pair t = heap.poll();long distance = t.first;int ver = t.second;if (st[ver])continue;st[ver] = true;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 Pair(dist[j], j));}}}if (dist[n] == Integer.MAX_VALUE)return -1;elsereturn dist[n];}
}class Pair implements Comparable<Pair> {public long first;public int second;public Pair() {}public Pair(long a, int b) {this.first = a;this.second = b;}@Overridepublic int compareTo(Pair o) {return (int)Math.signum(this.first - o.first);}
}

bellman-ford

迭代 nnn 次,每次循环所有边(a,b,w)(a, b, w)(a,b,w),更新路径:dist[b] = min(dist[b], dist[a] + w);(松弛操作)。全部操作完后满足三角不等式:dist[b]≤dist[a]+wdist[b] ≤ dist[a] + wdist[b]dist[a]+w

  • 例题:AcWing 853. 有边数限制的最短路
import java.util.*;public class Main {public static int n;public static int m;public static int k;public static int[] dist;public static int[] backup;public static Edge[] edge;public static final int MAX = 0x3f3f3f3f;public static void main(String[] args) {Scanner scanner= new Scanner(System.in);n = scanner.nextInt();m = scanner.nextInt();k = scanner.nextInt();dist = new int[n + 10];Arrays.fill(dist, MAX);dist[1] = 0;edge = new Edge[m + 10];for (int i = 0; i < m; i++) {int a = scanner.nextInt();int b = scanner.nextInt();int w = scanner.nextInt();edge[i] = new Edge(a, b, w);}int t = bellmanFord();if (t > MAX >> 1)System.out.println("impossible");elseSystem.out.println(t);}public static int bellmanFord() {for (int i = 0; i < k; i++) {backup = Arrays.copyOf(dist, dist.length);for (int j = 0; j < m; j++) {int a = edge[j].a;int b = edge[j].b;int w = edge[j].w;dist[b] = Math.min(dist[b], backup[a] + w);}}return dist[n];}
}class Edge {public int a;public int b;public int w;public Edge(int a, int b, int w) {this.a = a;this.b = b;this.w = w;}
}

SPFA

针对 bellman-ford 算法的 dist[b] = Math.min(dist[b], backup[a] + w); 使用队列进行优化。

  • 例题:AcWing 851. spfa求最短路
  • 例题:AcWing 852. spfa判断负环
import java.util.*;public class Main {public static int n;public static int m;public static int[] h;public static int[] w;public static int[] e;public static int[] ne;public static int idx;public static int[] dist;public static boolean[] st;public static final int MAX = 0x3f3f3f3f;public static void main(String[] args) {Scanner scanner = new Scanner(System.in);n = scanner.nextInt();m = scanner.nextInt();h = new int[n + 10];w = new int[m + 10];e = new int[m + 10];ne = new int[m + 10];dist = new int[n + 10];st = new boolean[n + 10];Arrays.fill(h, -1);while (m-- != 0) {int a = scanner.nextInt();int b = scanner.nextInt();int c = scanner.nextInt();add(a, b, c);}int t = spfa();if (t > MAX >> 1)System.out.println("impossible");elseSystem.out.println(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() {Arrays.fill(dist, MAX);dist[1] = 0;Queue<Integer> q = new ArrayDeque<>();q.add(1);st[1] = true;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 (dist[j] > dist[t] + w[i]) {dist[j] = dist[t] + w[i];if (!st[j]) {q.add(j);st[j] = true;}}}}return dist[n];}
}

Floyd

基于动态规划。枚举 k,i,jk, i, jk,i,j 更新路径:d(i, j) = min(d(i, j), d(i, k) + d(k, j));

  • 例题:AcWing 854. Floyd求最短路
import java.util.*;public class Main {public static int n;public static int m;public static int k;public static int[][] d;public static final int MAX = 0x3f3f3f3f;public static void main(String[] args) {Scanner scanner = new Scanner(System.in);n = scanner.nextInt();m = scanner.nextInt();k = scanner.nextInt();d = new int[n + 10][n + 10];for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)if (i == j)d[i][j] = 0;elsed[i][j] = MAX;while (m-- != 0) {int a = scanner.nextInt();int b = scanner.nextInt();int w = scanner.nextInt();d[a][b] = Math.min(d[a][b], w);}floyd();while (k-- != 0) {int a = scanner.nextInt();int b = scanner.nextInt();if (d[a][b] > MAX >> 1)System.out.println("impossible");elseSystem.out.println(d[a][b]);}}public static void floyd() {for (int k = 1; k <= n; k++)for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)d[i][j] = Math.min(d[i][j], d[i][k] + d[k][j]);}
}
http://www.xdnf.cn/news/20110.html

相关文章:

  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(26):文法+单词第8回3 复习 +考え方6
  • LangGraph节点完整组成与要求详解
  • 9月5日星期五今日早报简报微语报早读
  • 【代码随想录算法训练营——Day3】链表——203.移除链表元素、707.设计链表、206.反转链表
  • LangChain :Chain
  • WIN11控制面板中丢失BitLocker,找回WIN10控制面板中的BitLocker驱动器加密设置
  • 今日行情明日机会——20250905
  • 雨后阳光为何更强烈?
  • Spring整合MQTT使用
  • ai连接怡和达进行非标选型 抓包失败
  • 阿瓦隆 A1566HA 2U 480T矿机参数解析:性能与能效深入分析
  • 问题三ai思路
  • 项目经理为什么要有一张PMP®认证?
  • 力扣hot100:旋转图像(48)(详细图解以及核心思路剖析)
  • 代码可读性的详细入门
  • 1.10 虚拟内存管理机制
  • 【面板数据】全球数字贸易规则一体化程度数据及参考文献(2000-2024年)
  • 11.1.7 cpp客户端上传测试和文件引用计数测试
  • 【数据结构——哈夫曼树】
  • 理解UE4中C++17的...符号及enable_if_t的用法及SFINAE思想
  • Redis到底什么,该怎么用
  • JavaWeb —— 登录校验
  • AOI 检测准、机床运行稳?杰和 AR707 撑起工控 “精准 + 高效”
  • biocmanager安装 库 老是提示网络连接错误 才尝试各种办法
  • 「数据获取」《中国劳动统计年鉴》(1991-2024)
  • linux inotify 功能详解
  • MySQL锁篇-锁类型
  • 解析豆科系统发育冲突原因
  • 无字母数字命令执行
  • UC Berkeley 开源大世界模型(LWM):多模态大模型领域世界模型技术新进展