1type Input = Vec<Vec<usize>>;
13
14pub fn parse(input: &str) -> Input {
16 let mut graph = vec![Vec::new(); 26 * 26 * 26];
17
18 for line in input.lines() {
19 let mut edges = line.split_ascii_whitespace();
20 let from = edges.next().unwrap();
21 graph[to_index(from)].extend(edges.map(to_index));
22 }
23
24 graph
25}
26
27pub fn part1(input: &Input) -> u64 {
28 paths(input, "you", "out")
29}
30
31pub fn part2(input: &Input) -> u64 {
35 let fft_to_dac = paths(input, "fft", "dac");
36 if fft_to_dac == 0 {
38 paths(input, "svr", "dac") * paths(input, "dac", "fft") * paths(input, "fft", "out")
39 } else {
40 paths(input, "svr", "fft") * fft_to_dac * paths(input, "dac", "out")
41 }
42}
43
44fn paths(input: &Input, from: &str, to: &str) -> u64 {
45 let mut cache = vec![u64::MAX; input.len()];
46 cache[to_index(to)] = 1;
47 dfs(input, &mut cache, to_index(from))
48}
49
50fn dfs(input: &Input, cache: &mut [u64], node: usize) -> u64 {
51 if cache[node] == u64::MAX {
52 cache[node] = input[node].iter().map(|&next| dfs(input, cache, next)).sum();
53 }
54
55 cache[node]
56}
57
58fn to_index(s: &str) -> usize {
60 s.bytes().take(3).fold(0, |acc, b| 26 * acc + usize::from(b - b'a'))
61}