use std::cmp::Reverse; use std::collections::BinaryHeap; /// Computes shortest-path distances from `source` in a graph with non-negative weights. /// /// The graph is an adjacency list where `graph[u]` contains `(v, weight)` edges. /// Unreachable vertices are returned as `None`. pub fn dijkstra(graph: &[Vec<(usize, u64)>], source: usize) -> Vec> { let mut dist = vec![u64::MAX; graph.len()]; if source >= graph.len() { return vec![None; graph.len()]; } let mut heap = BinaryHeap::new(); dist[source] = 0; heap.push(Reverse((0_u64, source))); while let Some(Reverse((cost, u))) = heap.pop() { // Ignore stale heap entries produced before a shorter path was found. if cost != dist[u] { continue; } for &(v, weight) in &graph[u] { if v >= graph.len() { continue; } if let Some(next_cost) = cost.checked_add(weight) { if next_cost < dist[v] { dist[v] = next_cost; heap.push(Reverse((next_cost, v))); } } } } dist.into_iter() .map(|d| if d == u64::MAX { None } else { Some(d) }) .collect() } #[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 marks_unreachable_vertices() { let graph = vec![ vec![(1, 7)], vec![], vec![(0, 3)], ]; assert_eq!(dijkstra(&graph, 0), vec![Some(0), Some(7), None]); } }