use std::cmp::Reverse; use std::collections::BinaryHeap; /// Computes shortest distances from `start` in a directed, non-negative graph. /// /// Each adjacency-list entry contains `(neighbor, edge_weight)`. fn dijkstra(graph: &[Vec<(usize, u64)>], start: usize) -> Vec> { assert!(start < graph.len(), "start vertex is out of bounds"); let mut distances = vec![None; graph.len()]; let mut queue = BinaryHeap::new(); distances[start] = Some(0); queue.push(Reverse((0_u64, start))); while let Some(Reverse((distance, vertex))) = queue.pop() { // Ignore stale queue entries. if distances[vertex] != Some(distance) { continue; } for &(neighbor, weight) in &graph[vertex] { assert!(neighbor < graph.len(), "neighbor is out of bounds"); // An overflowing path cannot be represented by u64. 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() { 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::*; #[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_unset() { let graph = vec![vec![(1, 7)], vec![], vec![]]; assert_eq!(dijkstra(&graph, 0), vec![Some(0), Some(7), None]); } }