SPFA 算法介绍和实现

x33g5p2x  于2022-07-10 转载在 其他  
字(1.8k)|赞(0)|评价(0)|浏览(415)

一 点睛

SPFA 算法是 Bellman-Ford 算法的队列优化算法,通常用于求解负权边的单源最短路径,以及判断负环。在最坏的情况下,SPFA 算法的时间复杂度和 Bellman-Ford 算法相同,为O(nm);但在系数图上运行效率较高,为 O(km),其中 k 是一个较小的常数。

二 算法步骤

1 创建一个队列,首先源点 u 入队,标记 u 在队列中,u 的入队次数加1。

2 松弛操作。取出队头节点 x,标记 x 不在队列中。扫描所有 x 的所有出边 i(x,v,w),如果 dis[v]>dis[x]+e[i].w,令  dis[v]=dis[x]+e[i].w。如果节点 v 不在队列中,判断 v 的入队此时加1后大于或等于 n,则说明有负环,退出;否则 v 入队,标记 v 在队列中。

3 重复松弛操作,直到队列为空。

三 算法实现

  1. package graph.spfa;
  2. import java.util.LinkedList;
  3. import java.util.Queue;
  4. import java.util.Scanner;
  5. public class Spfa {
  6. static final int maxn = 505;
  7. static final int maxe = 100001;
  8. static int n;
  9. static int m;
  10. static int cnt;
  11. static node e[] = new node[maxn];
  12. static int head[] = new int[maxn];
  13. static int dis[] = new int[maxn];
  14. static int sum[] = new int[maxn];
  15. static boolean vis[] = new boolean[maxn];
  16. static {
  17. for (int i = 0; i < e.length; i++) {
  18. e[i] = new node();
  19. }
  20. for (int i = 0; i < head.length; i++) {
  21. head[i] = -1;
  22. }
  23. }
  24. static void add(int u, int v, int w) {
  25. e[cnt].to = v;
  26. e[cnt].next = head[u];
  27. e[cnt].w = w;
  28. head[u] = cnt++;
  29. }
  30. static boolean spfa(int u) {
  31. Queue<Integer> q = new LinkedList<>();
  32. for (int i = 0; i < vis.length; i++) {
  33. vis[i] = false;
  34. }
  35. // 统计入队的次数
  36. for (int i = 0; i < sum.length; i++) {
  37. sum[i] = 0;
  38. }
  39. for (int i = 0; i < dis.length; i++) {
  40. dis[i] = 0x3f;
  41. }
  42. vis[u] = true;
  43. dis[u] = 0;
  44. sum[u]++;
  45. q.add(u);
  46. while (!q.isEmpty()) {
  47. int x = q.peek();
  48. q.poll();
  49. vis[x] = false;
  50. for (int i = head[x]; i >= 0; i = e[i].next) {
  51. int v = e[i].to;
  52. if (dis[v] > dis[x] + e[i].w) {
  53. dis[v] = dis[x] + e[i].w;
  54. if (!vis[v]) {
  55. if (++sum[v] >= n)
  56. return true;
  57. vis[v] = true;
  58. q.add(v);
  59. }
  60. }
  61. }
  62. }
  63. return false;
  64. }
  65. static void print() { // 输出源点到其它节点的最短距离
  66. System.out.println("最短距离:");
  67. for (int i = 1; i <= n; i++)
  68. System.out.print(dis[i] + " ");
  69. System.out.println();
  70. }
  71. public static void main(String[] args) {
  72. cnt = 0;
  73. Scanner scanner = new Scanner(System.in);
  74. n = scanner.nextInt();
  75. m = scanner.nextInt();
  76. int u, v, w;
  77. for (int i = 1; i <= m; i++) {
  78. u = scanner.nextInt();
  79. v = scanner.nextInt();
  80. w = scanner.nextInt();
  81. add(u, v, w);
  82. }
  83. if (spfa(1))
  84. System.out.println("有负环!");
  85. else
  86. print();
  87. }
  88. }
  89. class node {
  90. int to;
  91. int w;
  92. int next;
  93. }

四 测试

1 无负环情况

2 有负环情况

相关文章