From ac4c0f3838fd0a10dfa434e4ea5c679d7113c37c Mon Sep 17 00:00:00 2001 From: Jan-Bulthuis Date: Tue, 24 Dec 2024 15:20:16 +0100 Subject: [PATCH] day23 --- aoc_2024/src/day23.rs | 249 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 aoc_2024/src/day23.rs diff --git a/aoc_2024/src/day23.rs b/aoc_2024/src/day23.rs new file mode 100644 index 0000000..c5b81ec --- /dev/null +++ b/aoc_2024/src/day23.rs @@ -0,0 +1,249 @@ +use aoc_runner_derive::{aoc, aoc_generator}; +use hashbrown::{HashMap, HashSet}; + +type Input = (usize, [Vec; 26 * 26], HashMap); + +#[aoc_generator(day23)] +fn parse(input: &str) -> Input { + let mut i = 0; + let mut names = HashMap::new(); + let mut ids = HashMap::new(); + let mut adj_list = [const { Vec::new() }; 26 * 26]; + input.lines().for_each(|line| { + let mut splits = line.split('-'); + let left = splits.next().unwrap().to_string(); + let right = splits.next().unwrap().to_string(); + + let left_id = { + *ids.entry(left.clone()).or_insert_with(|| { + let id = i; + i += 1; + names.insert(id, left); + id + }) + }; + let right_id = { + *ids.entry(right.clone()).or_insert_with(|| { + let id = i; + i += 1; + names.insert(id, right); + id + }) + }; + + adj_list[left_id].push(right_id); + adj_list[right_id].push(left_id); + }); + + (i, adj_list, names) +} + +#[aoc(day23, part1)] +fn part1(input: &Input) -> usize { + let num = input.0; + let adj_list = &input.1; + let names = &input.2; + + (0..num) + .filter(|id| names[id].starts_with("t")) + .flat_map(|id| { + let mut three_groups = HashSet::new(); + let adj = &adj_list[id]; + + for left in 0..adj.len() { + for right in left + 1..adj.len() { + if adj_list[adj[left]].contains(&adj[right]) { + let mut group = [id, adj[left], adj[right]]; + group.sort(); + three_groups.insert((group[0], group[1], group[2])); + } + } + } + + three_groups + }) + .collect::>() + .into_iter() + .count() +} + +#[aoc(day23, part2)] +fn part2(input: &Input) -> String { + let num = input.0; + let adj_list = &input.1; + let names = &input.2; + + let max_clique = (0..num) + .filter(|id| names[id].starts_with("t")) + .flat_map(|id| { + let mut three_groups = HashSet::new(); + let adj = &adj_list[id]; + + for left in 0..adj.len() { + for right in left + 1..adj.len() { + if adj_list[adj[left]].contains(&adj[right]) { + let mut group = [id, adj[left], adj[right]]; + group.sort(); + three_groups.insert((group[0], group[1], group[2])); + } + } + } + + three_groups + }) + .collect::>() + .into_iter() + .flat_map(|(a, b, c)| { + let clique = vec![a, b, c]; + expand_cliques(clique, num, adj_list) + }) + .max_by_key(|clique| clique.len()) + .unwrap(); + + let mut names = max_clique + .iter() + .map(|id| names[id].clone()) + .collect::>(); + names.sort(); + + names.join(",") +} + +fn expand_cliques(current: Vec, num: usize, adj: &[Vec]) -> Vec> { + let mut expansions: Vec> = vec![current.clone()]; + + for node in 0..num { + if current.contains(&node) { + continue; + } + + if !current + .iter() + .all(|clique_node| adj[*clique_node].contains(&node)) + { + continue; + } + + let mut pushed = false; + for clique in &mut expansions { + if clique + .iter() + .all(|clique_node| adj[*clique_node].contains(&node)) + { + clique.push(node); + pushed = true; + continue; + } + } + if !pushed { + let mut new_clique = current.clone(); + new_clique.push(node); + expansions.push(new_clique); + } + } + + expansions +} + +// fn max_clique(r: &mut HashSet, coloring: &[i32]) { +// let mut q = HashSet::new(); +// let mut q_max = HashSet::new(); + +// while !r.is_empty() { +// let p = *r.iter().max_by_key(|node| coloring[**node]).unwrap(); +// r.remove(&p); +// if q.len() + coloring[p] > q_max.len() { +// q.insert(p); +// q.remove(p); +// } else { +// return; +// } +// } +// } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn part1_example() { + assert_eq!( + part1(&parse( + "kh-tc +qp-kh +de-cg +ka-co +yn-aq +qp-ub +cg-tb +vc-aq +tb-ka +wh-tc +yn-cg +kh-ub +ta-co +de-co +tc-td +tb-wq +wh-td +ta-ka +td-qp +aq-cg +wq-ub +ub-vc +de-ta +wq-aq +wq-vc +wh-yn +ka-de +kh-ta +co-tc +wh-qp +tb-vc +td-yn" + )), + 7 + ); + } + + #[test] + fn part2_example() { + assert_eq!( + part2(&parse( + "kh-tc +qp-kh +de-cg +ka-co +yn-aq +qp-ub +cg-tb +vc-aq +tb-ka +wh-tc +yn-cg +kh-ub +ta-co +de-co +tc-td +tb-wq +wh-td +ta-ka +td-qp +aq-cg +wq-ub +ub-vc +de-ta +wq-aq +wq-vc +wh-yn +ka-de +kh-ta +co-tc +wh-qp +tb-vc +td-yn" + )), + "co,de,ka,ta" + ); + } +}