Rust/2024/23: add solution
This commit is contained in:
parent
a7315636ef
commit
fd4be9f755
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
95
Rust/2024/23.rs
Normal 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);
|
|
@ -21,7 +21,7 @@ aoc::year! {
|
|||
"20.rs",
|
||||
"21.rs",
|
||||
"22.rs",
|
||||
// "23.rs",
|
||||
"23.rs",
|
||||
// "24.rs",
|
||||
// "25.rs",
|
||||
}
|
||||
|
|
|
@ -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
238
Rust/lib/bitset.rs
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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
32
examples/2024/23/1
Normal 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
1
examples/2024/23/1.1
Normal file
|
@ -0,0 +1 @@
|
|||
7
|
1
examples/2024/23/1.2
Normal file
1
examples/2024/23/1.2
Normal file
|
@ -0,0 +1 @@
|
|||
co,de,ka,ta
|
Loading…
Add table
Add a link
Reference in a new issue