use std::cmp::Reverse; use std::collections::BinaryHeap; /// Computes shortest distances from `source`. /// /// Each adjacency-list entry is `(neighbor, nonnegative_edge_weight)`. /// Unreachable vertices have distance `None`. pub fn dijkstra(graph: &[Vec<(usize, u64)>], source: usize) -> Vec> { assert!(source < graph.len(), "source vertex is out of bounds"); let mut distances = vec![None; graph.len()]; let mut queue = BinaryHeap::new(); distances[source] = Some(0); queue.push(Reverse((0_u64, source))); while let Some(Reverse((distance, vertex))) = queue.pop() { // Ignore stale queue entries superseded by a shorter path. if distances[vertex] != Some(distance) { continue; } for &(neighbor, weight) in &graph[vertex] { assert!(neighbor < graph.len(), "neighbor vertex is out of bounds"); // An overflowing sum cannot represent a valid u64 distance. let Some(candidate) = distance.checked_add(weight) else { continue; }; if distances[neighbor].is_none_or(|current| candidate < current) { distances[neighbor] = Some(candidate); queue.push(Reverse((candidate, neighbor))); } } } distances } fn main() {} #[cfg(test)] mod tests { use super::dijkstra; #[test] fn finds_shortest_paths() { let graph = vec![ vec![(1, 4), (2, 1)], vec![(3, 1)], vec![(1, 2), (3, 5)], vec![], ]; assert_eq!( dijkstra(&graph, 0), vec![Some(0), Some(3), Some(1), Some(4)] ); } #[test] fn leaves_unreachable_vertices_unvisited() { let graph = vec![vec![(1, 7)], vec![], vec![(0, 2)]]; assert_eq!(dijkstra(&graph, 0), vec![Some(0), Some(7), None]); } }