diff --git a/1851/src/bin/e.rs b/1851/src/bin/e.rs index 30bcf6f..de0b15c 100644 --- a/1851/src/bin/e.rs +++ b/1851/src/bin/e.rs @@ -25,34 +25,59 @@ impl Way { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Mark { + None, + Temporary, + Permanent, +} + +fn toposort(ways: &[Way], marks: &mut Vec) -> Vec { + fn visit(ways: &[Way], marks: &mut Vec, ordering: &mut Vec, u: usize) { + match marks[u] { + Mark::None => { + marks[u] = Mark::Temporary; + + for v in &ways[u].required { + visit(ways, marks, ordering, v - 1); + } + + marks[u] = Mark::Permanent; + ordering.push(u); + } + Mark::Temporary => unreachable!("no loops should be present"), + Mark::Permanent => { /* no-op */ } + } + } + + let mut ordering = vec![]; + + for i in 0..marks.len() { + visit(ways, marks, &mut ordering, i); + } + + ordering +} + fn find_costs(costs: &mut Vec, unlimited: Vec, ways: Vec) { - let mut is_final = vec![false; costs.len()]; + let mut marks = vec![Mark::None; costs.len()]; // set cost of unlimited for i in unlimited { costs[i - 1] = 0; - is_final[i - 1] = true; + marks[i - 1] = Mark::Permanent; } // set cost of inconstructible - let mut q: HashSet = HashSet::new(); for (i, way) in ways.iter().enumerate() { if way.estimated_cost(costs) == u64::MAX { - is_final[i] = true; - } else { - q.insert(i); + marks[i] = Mark::Permanent; } } - while let Some(i) = q - .iter() - .filter(|i| !is_final[**i]) - .min_by_key(|i| ways[**i].estimated_cost(costs)) - .map(|i| *i) - { + // do toposort to find the ideal order + for i in toposort(&ways, &mut marks) { costs[i] = min(costs[i], ways[i].estimated_cost(costs)); - is_final[i] = true; - q.remove(&i); } }