最短路径-Dijkstra

  1. use std::cmp::Reverse;
  2. use std::collections::{BTreeMap, BinaryHeap};
  3. use std::ops::Add;
  4. type Graph<V, E> = BTreeMap<V, BTreeMap<V, E>>;
  5. // performs Dijsktra's algorithm on the given graph from the given start
  6. // the graph is a positively-weighted undirected graph
  7. //
  8. // returns a map that for each reachable vertex associates the distance and the predecessor
  9. // since the start has no predecessor but is reachable, map[start] will be None
  10. pub fn dijkstra<V: Ord + Copy, E: Ord + Copy + Add<Output = E>>(
  11. graph: &Graph<V, E>,
  12. start: &V,
  13. ) -> BTreeMap<V, Option<(V, E)>> {
  14. let mut ans = BTreeMap::new();
  15. let mut prio = BinaryHeap::new();
  16. // start is the special case that doesn't have a predecessor
  17. ans.insert(*start, None);
  18. for (new, weight) in &graph[start] {
  19. ans.insert(*new, Some((*start, *weight)));
  20. prio.push(Reverse((*weight, new, start)));
  21. }
  22. while let Some(Reverse((dist_new, new, prev))) = prio.pop() {
  23. match ans[new] {
  24. // what we popped is what is in ans, we'll compute it
  25. Some((p, d)) if p == *prev && d == dist_new => {}
  26. // otherwise it's not interesting
  27. _ => continue,
  28. }
  29. for (next, weight) in &graph[new] {
  30. match ans.get(next) {
  31. // if ans[next] is a lower dist than the alternative one, we do nothing
  32. Some(Some((_, dist_next))) if dist_new + *weight >= *dist_next => {}
  33. // if ans[next] is None then next is start and so the distance won't be changed, it won't be added again in prio
  34. Some(None) => {}
  35. // the new path is shorter, either new was not in ans or it was farther
  36. _ => {
  37. ans.insert(*next, Some((*new, *weight + dist_new)));
  38. prio.push(Reverse((*weight + dist_new, next, new)));
  39. }
  40. }
  41. }
  42. }
  43. ans
  44. }
  45. #[cfg(test)]
  46. mod tests {
  47. use super::{dijkstra, Graph};
  48. use std::collections::BTreeMap;
  49. fn add_edge<V: Ord + Copy, E: Ord>(graph: &mut Graph<V, E>, v1: V, v2: V, c: E) {
  50. graph.entry(v1).or_insert_with(BTreeMap::new).insert(v2, c);
  51. graph.entry(v2).or_insert_with(BTreeMap::new);
  52. }
  53. #[test]
  54. fn single_vertex() {
  55. let mut graph: Graph<usize, usize> = BTreeMap::new();
  56. graph.insert(0, BTreeMap::new());
  57. let mut dists = BTreeMap::new();
  58. dists.insert(0, None);
  59. assert_eq!(dijkstra(&graph, &0), dists);
  60. }
  61. #[test]
  62. fn single_edge() {
  63. let mut graph = BTreeMap::new();
  64. add_edge(&mut graph, 0, 1, 2);
  65. let mut dists_0 = BTreeMap::new();
  66. dists_0.insert(0, None);
  67. dists_0.insert(1, Some((0, 2)));
  68. assert_eq!(dijkstra(&graph, &0), dists_0);
  69. let mut dists_1 = BTreeMap::new();
  70. dists_1.insert(1, None);
  71. assert_eq!(dijkstra(&graph, &1), dists_1);
  72. }
  73. #[test]
  74. fn tree_1() {
  75. let mut graph = BTreeMap::new();
  76. let mut dists = BTreeMap::new();
  77. dists.insert(1, None);
  78. for i in 1..100 {
  79. add_edge(&mut graph, i, i * 2, i * 2);
  80. add_edge(&mut graph, i, i * 2 + 1, i * 2 + 1);
  81. match dists[&i] {
  82. Some((_, d)) => {
  83. dists.insert(i * 2, Some((i, d + i * 2)));
  84. dists.insert(i * 2 + 1, Some((i, d + i * 2 + 1)));
  85. }
  86. None => {
  87. dists.insert(i * 2, Some((i, i * 2)));
  88. dists.insert(i * 2 + 1, Some((i, i * 2 + 1)));
  89. }
  90. }
  91. }
  92. assert_eq!(dijkstra(&graph, &1), dists);
  93. }
  94. #[test]
  95. fn graph_1() {
  96. let mut graph = BTreeMap::new();
  97. add_edge(&mut graph, 'a', 'c', 12);
  98. add_edge(&mut graph, 'a', 'd', 60);
  99. add_edge(&mut graph, 'b', 'a', 10);
  100. add_edge(&mut graph, 'c', 'b', 20);
  101. add_edge(&mut graph, 'c', 'd', 32);
  102. add_edge(&mut graph, 'e', 'a', 7);
  103. let mut dists_a = BTreeMap::new();
  104. dists_a.insert('a', None);
  105. dists_a.insert('c', Some(('a', 12)));
  106. dists_a.insert('d', Some(('c', 44)));
  107. dists_a.insert('b', Some(('c', 32)));
  108. assert_eq!(dijkstra(&graph, &'a'), dists_a);
  109. let mut dists_b = BTreeMap::new();
  110. dists_b.insert('b', None);
  111. dists_b.insert('a', Some(('b', 10)));
  112. dists_b.insert('c', Some(('a', 22)));
  113. dists_b.insert('d', Some(('c', 54)));
  114. assert_eq!(dijkstra(&graph, &'b'), dists_b);
  115. let mut dists_c = BTreeMap::new();
  116. dists_c.insert('c', None);
  117. dists_c.insert('b', Some(('c', 20)));
  118. dists_c.insert('d', Some(('c', 32)));
  119. dists_c.insert('a', Some(('b', 30)));
  120. assert_eq!(dijkstra(&graph, &'c'), dists_c);
  121. let mut dists_d = BTreeMap::new();
  122. dists_d.insert('d', None);
  123. assert_eq!(dijkstra(&graph, &'d'), dists_d);
  124. let mut dists_e = BTreeMap::new();
  125. dists_e.insert('e', None);
  126. dists_e.insert('a', Some(('e', 7)));
  127. dists_e.insert('c', Some(('a', 19)));
  128. dists_e.insert('d', Some(('c', 51)));
  129. dists_e.insert('b', Some(('c', 39)));
  130. assert_eq!(dijkstra(&graph, &'e'), dists_e);
  131. }
  132. }