use std::cmp::Reverse; use std::collections::BinaryHeap; /// Computes shortest distances from `start` in a directed graph. /// /// Each adjacency-list entry is `(neighbor, nonnegative_weight)`. /// Unreachable vertices have distance `None`. pub fn dijkstra(graph: &[Vec<(usize, u64)>], start: usize) -> Vec> { let mut distances = vec![None; graph.len()]; if start >= graph.len() { return distances; } let mut heap = BinaryHeap::new(); distances[start] = Some(0); heap.push(Reverse((0_u64, start))); while let Some(Reverse((distance, vertex))) = heap.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(), "edge points outside the graph"); // Overflow cannot produce a valid u64 path length. let Some(candidate) = distance.checked_add(weight) else { continue; }; if distances[neighbor].is_none_or(|current| candidate < current) { distances[neighbor] = Some(candidate); heap.push(Reverse((candidate, neighbor))); } } } distances } fn main() { let graph = vec![ vec![(1, 4), (2, 1)], vec![(3, 1)], vec![(1, 2), (3, 5)], vec![], ]; println!("{:?}", dijkstra(&graph, 0)); } #[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 preserves_unreachable_vertices() { let graph = vec![vec![(1, 7)], vec![], vec![]]; assert_eq!(dijkstra(&graph, 0), vec![Some(0), Some(7), None]); } }