This commit is contained in:
Jan-Bulthuis 2024-12-24 15:20:16 +01:00
parent b49467a59e
commit ac4c0f3838
1 changed files with 249 additions and 0 deletions

249
aoc_2024/src/day23.rs Normal file
View File

@ -0,0 +1,249 @@
use aoc_runner_derive::{aoc, aoc_generator};
use hashbrown::{HashMap, HashSet};
type Input = (usize, [Vec<usize>; 26 * 26], HashMap<usize, String>);
#[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::<HashSet<(usize, usize, usize)>>()
.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::<HashSet<(usize, usize, usize)>>()
.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::<Vec<String>>();
names.sort();
names.join(",")
}
fn expand_cliques(current: Vec<usize>, num: usize, adj: &[Vec<usize>]) -> Vec<Vec<usize>> {
let mut expansions: Vec<Vec<usize>> = 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<usize>, 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"
);
}
}