B5AQD4U2QCQGHWMJMU2DSDWLHRBEMHFXKKIAEYLN4B5HB2I5FFHAC
// I plan to use an unusual approach to this problem: it is not based on
// graph traversals but on transformations of directed graphs under which
// the number of paths bettween the start and end is invariant.
#![feature(hash_drain_filter)]
trim_graph(&mut graph);
println!("{} paths", count_paths(&graph));
}
fn count_paths(graph: &HashMap<usize, HashMap<usize, u128>>) -> u128 {
let mut q: VecDeque<(usize, BTreeSet<usize>)> = once((0, BTreeSet::new())).collect();
let mut r: HashMap<usize, HashMap<BTreeSet<usize>, u128>> = once((0, once((BTreeSet::new(), 1)).collect())).collect();
while let Some((n, p)) = q.pop_front() {
match (r.get(&n).and_then(|s| s.get(&p)), graph.get(&n)) {
(Some(c), Some(e)) => {
let c = *c;
let mut next_p = p.clone();
next_p.insert(n);
for (t, w) in e.iter().filter(|(t,_)| !p.contains(t)) {
let d = c * *w;
r.entry(*t).or_insert_with(|| HashMap::new()).entry(next_p.clone()).and_modify(|g| *g += d).or_insert(d);
q.push_back((*t, next_p.clone()));
}
}
_ => {}
}
}
r.get(&1).map(|z| z.iter().map(|(_,n)| *n).sum()).unwrap_or(0)
fn trim_graph(graph: &mut HashMap<usize, HashMap<usize, u128>>) -> bool {
use std::collections::HashSet;
let mut ever_changed = false;
loop {
let mut changed = false;
let reachable: HashSet<_> = graph
.values()
.flat_map(|e| e.keys())
.copied()
.chain(once(0))
.collect();
let reached: HashSet<_> = graph.keys().copied().collect();
graph
.drain_filter(|s, e| {
e.drain_filter(|t, n| {
if *n == 0 || !reached.contains(t) {
changed = true;
true
} else {
false
}
})
.for_each(drop);
if *s > 1 && (!reachable.contains(s) || e.is_empty()) {
changed = true;
true
} else {
false
}
})
.for_each(drop);
if changed {
ever_changed = true;
} else {
break;
}
}
ever_changed
}