最近看了《算法笔记》上面关于最短路径的部分,学习了一种之前没见过的算法:SPFA。
理论上SPFA算法会比Dijkstra快,顾而找了一题测试一下。
使用PAT A1072题,因为这题求最短路径的部分很单纯,没有其他的权,而且测试点的复杂度够高,能够看出时间上的差别。
题目链接

速度对比(重点看测试点4)

Dijkstra速度

image.png

SPFA

image.png
多次提交对比,Dijkstra算法都在50ms左右,而SPFA一直在10ms左右,可见SPFA确实比Dijkstra快不少,而且思路也不复杂,以后可以多多使用。

代码如下

  1. #include<bits/stdc++.h>
  2. #include<unordered_map>
  3. using namespace std;
  4. #define MAXNODE 1015
  5. #define INF 0x3ffffff
  6. #define G2index(G) ((n)+(G))
  7. #define index2G(index) ((index)-(G))
  8. struct Node
  9. {
  10. int v, dis;//目标与距离
  11. };
  12. int dis[MAXNODE];
  13. int n, m, k, dmax;
  14. bool used[MAXNODE], inqueue[MAXNODE];
  15. vector<Node> graph[MAXNODE];
  16. void Dijkstra(int start)
  17. {
  18. fill(dis, dis + MAXNODE, INF);
  19. fill(used, used + MAXNODE, false);
  20. dis[start] = 0;
  21. for (int i = 0; i < n + m - 1; i++) {
  22. int minnode = -1, mindis = INF;
  23. for (int j = 1; j <= n + m; j++) {
  24. if (!used[j] && dis[j] < mindis) {
  25. minnode = j;
  26. mindis = dis[j];
  27. }
  28. }
  29. if (minnode == -1)
  30. return;
  31. used[minnode] = true;
  32. int tdis = dis[minnode];
  33. for (Node node : graph[minnode]) {
  34. if (tdis + node.dis < dis[node.v]) {
  35. dis[node.v] = tdis + node.dis;
  36. }
  37. }
  38. }
  39. }
  40. void SPFA(int start)
  41. {
  42. fill(dis, dis + MAXNODE, INF);
  43. fill(inqueue, inqueue + MAXNODE, false);
  44. dis[start] = 0;
  45. int tdis = 0;
  46. queue<int> q;
  47. for (Node node : graph[start]) {
  48. if (tdis + node.dis < dis[node.v]) {
  49. dis[node.v] = node.dis + tdis;
  50. q.push(node.v);
  51. inqueue[node.v] = true;
  52. }
  53. }
  54. while (!q.empty()) {
  55. int nodeid = q.front();
  56. q.pop();
  57. inqueue[nodeid] = false;
  58. for (Node node : graph[nodeid]) {
  59. tdis = dis[nodeid];
  60. if (tdis + node.dis < dis[node.v]) {
  61. dis[node.v] = node.dis + tdis;
  62. if (!inqueue[node.v]) {
  63. q.push(node.v);
  64. inqueue[node.v] = true;
  65. }
  66. }
  67. }
  68. }
  69. }
  70. struct Ans
  71. {
  72. int Gid, mindis, totaldis;
  73. };
  74. vector<Ans> ans;
  75. void getans(int Gid)
  76. {
  77. int totaldis, mindis;
  78. mindis = INF;
  79. totaldis = 0;
  80. for (int i = 1; i <= n; i++) {
  81. if (dis[i] > dmax)
  82. return;
  83. if (dis[i] < mindis) {
  84. mindis = dis[i];
  85. }
  86. totaldis += dis[i];
  87. }
  88. ans.push_back(Ans{ Gid,mindis,totaldis });
  89. }
  90. int main() {
  91. scanf("%d%d%d%d", &n, &m, &k, &dmax);
  92. for (int i = 0; i < k; i++) {
  93. int c1, c2, dd;
  94. char cs1[10], cs2[10];
  95. scanf("%s%s%d", cs1, cs2, &dd);
  96. if (cs1[0] == 'G') {
  97. c1 = G2index(atoi(cs1 + 1));
  98. }
  99. else {
  100. c1 = atoi(cs1);
  101. }
  102. if (cs2[0] == 'G') {
  103. c2 = G2index(atoi(cs2 + 1));
  104. }
  105. else {
  106. c2 = atoi(cs2);
  107. }
  108. graph[c1].push_back(Node{ c2, dd });
  109. graph[c2].push_back(Node{ c1, dd });
  110. }
  111. for (int i = 1; i <= m; i++) {
  112. //Dijkstra(G2index(i));
  113. SPFA(G2index(i));
  114. getans(i);
  115. }
  116. Ans myans;
  117. myans.Gid = -1;
  118. myans.totaldis = INF;
  119. myans.mindis = 0;
  120. for (Ans a : ans) {
  121. if (a.mindis > myans.mindis)
  122. myans = a;
  123. else if (a.mindis == myans.mindis) {
  124. if (a.totaldis < myans.totaldis)
  125. myans = a;
  126. }
  127. }
  128. if (myans.Gid == -1) {
  129. printf("No Solution");
  130. return 0;
  131. }
  132. printf("G%d\n%.1lf %.1lf", myans.Gid, (double)myans.mindis, (double)myans.totaldis / n);
  133. return 0;
  134. }

代码思路就不写了,大家可以看算法笔记。