1851(E,rs): finish “Nastya and Potions”

* use toposort instead of a queue

Signed-off-by: Matej Focko <me@mfocko.xyz>
This commit is contained in:
Matej Focko 2023-07-30 19:36:04 +02:00
parent c0598833ea
commit 0108966775
Signed by: mfocko
GPG key ID: 7C47D46246790496

View file

@ -25,34 +25,59 @@ impl Way {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Mark {
None,
Temporary,
Permanent,
}
fn toposort(ways: &[Way], marks: &mut Vec<Mark>) -> Vec<usize> {
fn visit(ways: &[Way], marks: &mut Vec<Mark>, ordering: &mut Vec<usize>, 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<u64>, unlimited: Vec<usize>, ways: Vec<Way>) {
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<usize> = 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);
}
}