Rust/2024/23: add solution

This commit is contained in:
Felix Bargfeldt 2024-12-23 17:56:46 +01:00
parent a7315636ef
commit fd4be9f755
Signed by: Defelo
GPG key ID: 2A05272471204DD3
9 changed files with 374 additions and 3 deletions

File diff suppressed because one or more lines are too long

95
Rust/2024/23.rs Normal file
View file

@ -0,0 +1,95 @@
#![feature(test)]
#![expect(unstable_name_collisions)]
use aoc::bitset::BitSet;
use itertools::Itertools;
use rustc_hash::FxHashMap;
#[derive(Debug)]
struct Input {
graph: Vec<BitSet>,
names: Vec<String>,
}
fn setup(input: &str) -> Input {
let input = input.lines().map(|l| l.split('-').collect_tuple().unwrap());
let mut idx = FxHashMap::default();
for name in input.clone().flat_map(|(a, b)| [a, b]) {
let i = idx.len();
idx.entry(name).or_insert(i);
}
let mut graph = vec![BitSet::new(); idx.len()];
for (a, b) in input.map(|(a, b)| (idx[a], idx[b])) {
graph[a].insert(b);
graph[b].insert(a);
}
let mut names = vec![String::new(); idx.len()];
for (name, i) in idx {
names[i] = name.into();
}
Input { graph, names }
}
fn max_bron_kerbosch(r: BitSet, mut p: BitSet, mut x: BitSet, graph: &[BitSet]) -> Option<BitSet> {
if p.is_empty() && x.is_empty() {
return Some(r);
}
let mut out = None::<BitSet>;
let u = p.iter().chain(&x).next().unwrap();
for v in &(p.clone() - &graph[u]) {
let mut r = r.clone();
r.insert(v);
let n = &graph[v];
let result = max_bron_kerbosch(r, p.clone() & n, x.clone() & n, graph);
if result.as_ref().map(|s| s.len()) > out.as_ref().map(|s| s.len()) {
out = result;
}
p.remove(v);
x.insert(v);
}
out
}
fn part1(input: &Input) -> usize {
let t = &input
.names
.iter()
.enumerate()
.filter_map(|(i, name)| name.starts_with('t').then_some(i))
.collect::<BitSet>();
input
.graph
.iter()
.enumerate()
.flat_map(|(a, an)| {
an.iter().take_while(move |&b| b < a).flat_map(move |b| {
an.iter()
.take_while(move |&c| c < b)
.filter(move |&c| input.graph[b].contains(c))
.filter(move |&c| [a, b, c].into_iter().any(|i| t.contains(i)))
})
})
.count()
}
fn part2(input: &Input) -> String {
max_bron_kerbosch(
Default::default(),
(0..input.graph.len()).collect(),
Default::default(),
&input.graph,
)
.unwrap()
.into_iter()
.map(|i| input.names[i].as_str())
.sorted_unstable()
.intersperse(",")
.collect()
}
aoc::main!(2024, 23, ex: 1);

View file

@ -21,7 +21,7 @@ aoc::year! {
"20.rs",
"21.rs",
"22.rs",
// "23.rs",
"23.rs",
// "24.rs",
// "25.rs",
}

View file

@ -426,3 +426,6 @@ path = "2024/21.rs"
[[bin]]
name = "2024_22"
path = "2024/22.rs"
[[bin]]
name = "2024_23"
path = "2024/23.rs"

238
Rust/lib/bitset.rs Normal file
View file

@ -0,0 +1,238 @@
use std::{
iter,
ops::{BitAnd, BitOr, Sub},
};
use itertools::Itertools;
#[derive(Debug, Clone, Default)]
pub struct BitSet {
bits: Vec<u64>,
len: usize,
}
impl BitSet {
pub fn new() -> Self {
Self::default()
}
pub fn contains(&self, x: usize) -> bool {
let (i, j) = key(x);
i < self.bits.len() && self.bits[i] & j != 0
}
pub fn insert(&mut self, x: usize) {
let (i, j) = key(x);
self.extend_to_len(i + 1);
if self.bits[i] & j == 0 {
self.len += 1;
}
self.bits[i] |= j;
}
pub fn remove(&mut self, x: usize) {
let (i, j) = key(x);
if i < self.bits.len() {
if self.bits[i] & j != 0 {
self.len -= 1;
}
self.bits[i] &= !j;
}
}
pub fn shrink(&mut self) {
while self.bits.last() == Some(&0) {
self.bits.pop();
}
self.bits.shrink_to_fit();
}
fn extend_to_len(&mut self, len: usize) {
if len > self.bits.len() {
self.bits
.extend(iter::repeat(0).take(len - self.bits.len()));
}
}
pub fn iter(&self) -> BitSetIter<'_> {
self.into_iter()
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn len(&self) -> usize {
self.len
}
}
impl BitAnd<&Self> for BitSet {
type Output = Self;
fn bitand(mut self, rhs: &Self) -> Self::Output {
let mut removed = self
.bits
.iter()
.skip(rhs.bits.len())
.map(|x| x.count_ones())
.sum::<u32>();
self.bits.truncate(rhs.bits.len());
for (a, &b) in self.bits.iter_mut().zip(&rhs.bits) {
removed += (*a & !b).count_ones();
*a &= b;
}
self.len -= removed as usize;
self
}
}
impl BitOr<&Self> for BitSet {
type Output = Self;
fn bitor(mut self, rhs: &Self) -> Self::Output {
self.extend_to_len(rhs.bits.len());
let mut added = 0;
for (a, &b) in self.bits.iter_mut().zip(&rhs.bits) {
added += (!*a & b).count_ones();
*a |= b;
}
self.len += added as usize;
self
}
}
impl Sub<&Self> for BitSet {
type Output = Self;
fn sub(mut self, rhs: &Self) -> Self::Output {
let mut removed = 0;
for (a, &b) in self.bits.iter_mut().zip(&rhs.bits) {
removed += (*a & b).count_ones();
*a &= !b;
}
self.len -= removed as usize;
self
}
}
impl PartialEq for BitSet {
fn eq(&self, other: &Self) -> bool {
if self.len != other.len {
return false;
}
self.bits.iter().zip_longest(&other.bits).all(|x| {
let (a, b) = x.left_and_right();
a.unwrap_or(&0) == b.unwrap_or(&0)
})
}
}
impl Eq for BitSet {}
impl FromIterator<usize> for BitSet {
fn from_iter<T: IntoIterator<Item = usize>>(iter: T) -> Self {
let mut set = Self::new();
for x in iter {
set.insert(x);
}
set
}
}
pub struct BitSetIter<'a> {
i: usize,
j: usize,
set: &'a BitSet,
}
impl<'a> IntoIterator for &'a BitSet {
type Item = <Self::IntoIter as Iterator>::Item;
type IntoIter = BitSetIter<'a>;
fn into_iter(self) -> Self::IntoIter {
BitSetIter {
i: 0,
j: 0,
set: self,
}
}
}
impl Iterator for BitSetIter<'_> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
while *self.set.bits.get(self.i)? >> self.j == 0 {
self.i += 1;
self.j = 0;
}
while self.set.bits[self.i] & (1 << self.j) == 0 {
self.j += 1;
}
let x = (self.i << 6) | self.j;
self.j += 1;
if self.j == 64 {
self.j = 0;
self.i += 1;
}
Some(x)
}
}
fn key(x: usize) -> (usize, u64) {
(x >> 6, 1 << (x & 0x3f))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn set() {
let mut set = BitSet::new();
assert_eq!(set.iter().collect::<Vec<_>>(), []);
assert!(!set.contains(1));
assert!(!set.contains(2));
assert!(!set.contains(3));
assert!(!set.contains(1337));
assert_eq!(set.len(), 0);
set.insert(1);
set.insert(2);
set.insert(1337);
set.insert(3);
assert!(set.contains(1));
assert!(set.contains(2));
assert!(set.contains(3));
assert!(set.contains(1337));
assert_eq!(set.len(), 4);
assert_eq!(set.iter().collect::<Vec<_>>(), [1, 2, 3, 1337]);
set.remove(2);
assert_eq!(set.len(), 3);
assert_eq!(set.iter().collect::<Vec<_>>(), [1, 3, 1337]);
set.remove(1337);
assert_eq!(set.len(), 2);
assert_eq!(set, BitSet::from_iter([1, 3]));
assert_ne!(set.bits, BitSet::from_iter([1, 3]).bits);
assert_eq!(set.bits.len(), 21);
set.shrink();
assert_eq!(set.bits.len(), 1);
assert_eq!(set.iter().collect::<Vec<_>>(), [1, 3]);
}
#[test]
fn ops() {
let a = BitSet::from_iter([1, 2, 3]);
let b = BitSet::from_iter([3, 4]);
assert_eq!(a.clone() & &b, BitSet::from_iter([3]));
assert_eq!((a.clone() & &b).len(), 1);
assert_eq!(a.clone() | &b, BitSet::from_iter([1, 2, 3, 4]));
assert_eq!((a.clone() | &b).len(), 4);
assert_eq!(a.clone() - &b, BitSet::from_iter([1, 2]));
assert_eq!((a.clone() - &b).len(), 2);
}
}

View file

@ -4,6 +4,7 @@
pub use test::Bencher;
pub mod arrays;
pub mod bitset;
pub mod grid;
pub mod intcode;
pub mod iter_ext;

32
examples/2024/23/1 Normal file
View file

@ -0,0 +1,32 @@
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

1
examples/2024/23/1.1 Normal file
View file

@ -0,0 +1 @@
7

1
examples/2024/23/1.2 Normal file
View file

@ -0,0 +1 @@
co,de,ka,ta