competitive_library/graph/
dijkstra_restore_path.rs1use std::{cmp::Ordering, collections::BinaryHeap};
3
4#[derive(Debug, Clone, Eq)]
5pub struct Node {
6 position: usize,
7 cost: i64,
8 from: Option<usize>,
9}
10impl Node {
11 #[inline]
12 pub fn new(position: usize, cost: i64, from: Option<usize>) -> Self {
13 Node {
14 position,
15 cost,
16 from,
17 }
18 }
19}
20impl PartialEq for Node {
21 fn eq(&self, other: &Node) -> bool {
22 self.cost.eq(&other.cost)
23 }
24}
25impl PartialOrd for Node {
26 fn partial_cmp(&self, other: &Node) -> Option<Ordering> {
27 Some(self.cmp(other))
28 }
29}
30impl Ord for Node {
31 fn cmp(&self, other: &Self) -> Ordering {
32 other.cost.cmp(&self.cost)
33 }
34}
35
36pub fn dijkstra(
37 edge: &[Vec<(usize, i64)>],
38 start: usize,
39 end: usize,
40 vertex: usize,
41) -> Option<(i64, Vec<usize>)> {
42 let mut costs = vec![None; edge.len()];
43 let mut nodes = BinaryHeap::new();
44 let mut previous = vec![None; vertex];
45 nodes.push(Node::new(start, 0, None));
46
47 while let Some(Node {
48 position,
49 cost,
50 from,
51 }) = nodes.pop()
52 {
53 if costs[position].is_some() {
54 continue;
55 }
56
57 previous[position] = from;
58 costs[position] = Some(cost);
59 if position == end {
60 return Some((cost, restore_path(end, &previous)));
61 }
62
63 edge[position]
64 .iter()
65 .filter(|(to, c)| costs[*to].filter(|&d| d <= cost + c).is_none())
66 .for_each(|&(to, c)| {
67 nodes.push(Node::new(to, cost + c, Some(position)));
68 });
69 }
70 None
71}
72
73fn restore_path(end: usize, previous: &[Option<usize>]) -> Vec<usize> {
74 let mut buff = end;
75 let mut v = vec![buff];
76
77 while let Some(i) = previous[buff] {
78 buff = i;
79 v.push(buff);
80 }
81 v.reverse();
82 v
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88 #[test]
89 fn test_dijkstra() {
90 let graph = vec![
91 vec![(2, 10), (1, 1)],
92 vec![(3, 2)],
93 vec![(1, 1), (3, 3), (4, 1)],
94 vec![(0, 7), (4, 2)],
95 vec![],
96 ];
97 let l = graph.len();
98 for (start, end, ans) in &[
99 (0, 1, Some((1, vec![0, 1]))),
100 (0, 3, Some((3, vec![0, 1, 3]))),
101 (3, 0, Some((7, vec![3, 0]))),
102 (0, 4, Some((5, vec![0, 1, 3, 4]))),
103 (4, 0, None),
104 ] {
105 match dijkstra(&graph, *start, *end, l) {
106 Some((a, b)) => {
107 assert_eq!(a, ans.as_ref().unwrap().0);
108 assert_eq!(b, ans.as_ref().unwrap().1);
109 }
110 None => assert!(ans.is_none()),
111 }
112 }
113 }
114
115 #[test]
116 fn chooses_the_shorter_indirect_path() {
117 let graph = vec![vec![(1, 10), (2, 1)], vec![], vec![(1, 1)]];
118 assert_eq!(
119 dijkstra(&graph, 0, 1, graph.len()),
120 Some((2, vec![0, 2, 1]))
121 );
122 }
123}