1+ use utils:: bit:: BitIterator ;
12use utils:: prelude:: * ;
23
34/// Finding the largest clique in a graph.
5+ ///
6+ /// Assumes each node has the same degree N, and the largest clique contains N nodes.
47#[ derive( Clone , Debug ) ]
58pub struct Day23 {
6- nodes : Vec < Node > ,
7- }
8-
9- #[ derive( Clone , Debug ) ]
10- struct Node {
11- name : [ u8 ; 2 ] ,
12- edges : Vec < usize > ,
9+ nodes : [ [ u64 ; ( 26usize * 26 ) . div_ceil ( 64 ) ] ; 26 * 26 ] ,
10+ degree : u32 ,
1311}
1412
1513impl Day23 {
1614 pub fn new ( input : & str , _: InputType ) -> Result < Self , InputError > {
17- let mut indexes = [ None ; 26 * 26 ] ;
18- let mut nodes = vec ! [ ] ;
15+ let mut nodes = [ [ 0u64 ; 11 ] ; 676 ] ;
1916
2017 for item in parser:: byte_range ( b'a' ..=b'z' )
21- . repeat_n ( parser:: noop ( ) )
22- . repeat_n ( b'-' )
18+ . repeat_n :: < 2 , _ > ( parser:: noop ( ) )
19+ . repeat_n :: < 2 , _ > ( b'-' )
2320 . with_suffix ( parser:: eol ( ) )
2421 . parse_iterator ( input)
2522 {
2623 let [ n1, n2] = item?;
2724
28- let mut index_of = |n : [ u8 ; 2 ] | {
29- let i = 26 * ( n[ 0 ] - b'a' ) as usize + ( n[ 1 ] - b'a' ) as usize ;
30- match indexes[ i] {
31- Some ( index) => index,
32- None => {
33- let index = nodes. len ( ) ;
34- nodes. push ( Node {
35- name : n,
36- edges : Vec :: new ( ) ,
37- } ) ;
38- indexes[ i] = Some ( index) ;
39- index
40- }
41- }
42- } ;
25+ let index1 = 26 * ( n1[ 0 ] - b'a' ) as usize + ( n1[ 1 ] - b'a' ) as usize ;
26+ let index2 = 26 * ( n2[ 0 ] - b'a' ) as usize + ( n2[ 1 ] - b'a' ) as usize ;
27+
28+ nodes[ index1] [ index2 / 64 ] |= 1 << ( index2 % 64 ) ;
29+ nodes[ index2] [ index1 / 64 ] |= 1 << ( index1 % 64 ) ;
30+ }
4331
44- let index1 = index_of ( n1) ;
45- let index2 = index_of ( n2) ;
32+ let Some ( first_node) = nodes. iter ( ) . find ( |& b| b. iter ( ) . any ( |& n| n != 0 ) ) else {
33+ return Err ( InputError :: new ( input, 0 , "expected non-empty graph" ) ) ;
34+ } ;
4635
47- nodes[ index1] . edges . push ( index2) ;
48- nodes[ index2] . edges . push ( index1) ;
36+ let degree = first_node. iter ( ) . map ( |& n| n. count_ones ( ) ) . sum :: < u32 > ( ) ;
37+ if nodes. iter ( ) . any ( |& b| {
38+ let d = b. iter ( ) . map ( |& n| n. count_ones ( ) ) . sum :: < u32 > ( ) ;
39+ d != 0 && d != degree
40+ } ) {
41+ return Err ( InputError :: new (
42+ input,
43+ 0 ,
44+ "expected all nodes to have same degree" ,
45+ ) ) ;
4946 }
5047
51- Ok ( Self { nodes } )
48+ Ok ( Self { nodes, degree } )
5249 }
5350
5451 #[ must_use]
5552 pub fn part1 ( & self ) -> u32 {
5653 let mut count = 0 ;
57- for ( i1 , n1 ) in self . nodes . iter ( ) . enumerate ( ) {
58- for ( i2 , n2 ) in n1 . edges . iter ( ) . map ( | & i| ( i , & self . nodes [ i ] ) ) {
59- if i1 > i2 {
60- continue ;
54+ for n1 in 0 .. self . nodes . len ( ) {
55+ for n2 in self . neighbors ( n1 ) {
56+ if n2 > n1 {
57+ break ;
6158 }
62- for ( i3, n3) in n2. edges . iter ( ) . map ( |& i| ( i, & self . nodes [ i] ) ) {
63- if i2 < i3
64- && n1. edges . contains ( & i3)
65- && ( n1. name [ 0 ] == b't' || n2. name [ 0 ] == b't' || n3. name [ 0 ] == b't' )
66- {
59+ for n3 in Self :: iter ( Self :: intersect ( self . nodes [ n1] , self . nodes [ n2] ) ) {
60+ if n3 > n2 {
61+ break ;
62+ }
63+
64+ // 19 = b't' - b'a'
65+ if n1 / 26 == 19 || n2 / 26 == 19 || n3 / 26 == 19 {
6766 count += 1 ;
6867 }
6968 }
@@ -74,46 +73,62 @@ impl Day23 {
7473
7574 #[ must_use]
7675 pub fn part2 ( & self ) -> String {
77- let mut assigned = vec ! [ false ; self . nodes. len( ) ] ;
78- let mut node_lists = Vec :: with_capacity ( self . nodes . len ( ) ) ;
7976 for i in 0 ..self . nodes . len ( ) {
80- if !assigned[ i] {
81- let c = node_lists. len ( ) ;
82- node_lists. push ( Vec :: new ( ) ) ;
83- self . try_add ( i, & mut assigned, & mut node_lists[ c] ) ;
84- }
85- }
77+ ' sets: for skip in self . neighbors ( i) {
78+ if skip > i {
79+ break ;
80+ }
8681
87- let mut nodes = node_lists. into_iter ( ) . max_by_key ( |l| l. len ( ) ) . unwrap ( ) ;
88- nodes. sort_unstable_by_key ( |& n| self . nodes [ n] . name ) ;
89- nodes
90- . iter ( )
91- . fold ( String :: with_capacity ( nodes. len ( ) * 3 ) , |mut acc, & i| {
92- if !acc. is_empty ( ) {
93- acc. push ( ',' ) ;
82+ // Set of N nodes is (neighbours + starting node - skipped neighbour)
83+ let mut connected = self . nodes [ i] ;
84+ connected[ i / 64 ] |= 1 << ( i % 64 ) ;
85+ connected[ skip / 64 ] &= !( 1 << ( skip % 64 ) ) ;
86+
87+ for n in self . neighbors ( i) . filter ( |& n| n != skip) {
88+ connected = Self :: intersect ( connected, self . nodes [ n] ) ;
89+ connected[ n / 64 ] |= 1 << ( n % 64 ) ;
90+
91+ if connected. iter ( ) . map ( |& n| n. count_ones ( ) ) . sum :: < u32 > ( ) != self . degree {
92+ continue ' sets;
93+ }
9494 }
95- acc. push ( self . nodes [ i] . name [ 0 ] as char ) ;
96- acc. push ( self . nodes [ i] . name [ 1 ] as char ) ;
97- acc
98- } )
99- }
10095
101- fn try_add ( & self , n : usize , assigned : & mut [ bool ] , group : & mut Vec < usize > ) {
102- for & existing in group. iter ( ) {
103- if !self . nodes [ n] . edges . contains ( & existing) {
104- return ;
96+ return Self :: iter ( connected) . fold ( String :: new ( ) , |mut acc, i| {
97+ if !acc. is_empty ( ) {
98+ acc. push ( ',' ) ;
99+ }
100+ let name = [ b'a' + ( i / 26 ) as u8 , b'a' + ( i % 26 ) as u8 ] ;
101+ acc. push ( name[ 0 ] as char ) ;
102+ acc. push ( name[ 1 ] as char ) ;
103+ acc
104+ } ) ;
105105 }
106106 }
107107
108- group . push ( n ) ;
109- assigned [ n ] = true ;
108+ panic ! ( "no solution found" )
109+ }
110110
111- for & neighbour in self . nodes [ n] . edges . iter ( ) {
112- if !assigned[ neighbour] {
113- self . try_add ( neighbour, assigned, group) ;
114- }
111+ #[ inline]
112+ fn neighbors ( & self , n : usize ) -> impl Iterator < Item = usize > {
113+ Self :: iter ( self . nodes [ n] )
114+ }
115+
116+ #[ inline]
117+ fn iter ( bitset : [ u64 ; 11 ] ) -> impl Iterator < Item = usize > {
118+ bitset. into_iter ( ) . enumerate ( ) . flat_map ( |( element, b) | {
119+ BitIterator :: ones ( b) . map ( move |( bit, _) | element * 64 + bit as usize )
120+ } )
121+ }
122+
123+ #[ inline]
124+ fn intersect ( mut bitset1 : [ u64 ; 11 ] , bitset2 : [ u64 ; 11 ] ) -> [ u64 ; 11 ] {
125+ for ( a, & b) in bitset1. iter_mut ( ) . zip ( bitset2. iter ( ) ) {
126+ * a &= b;
115127 }
128+ bitset1
116129 }
117130}
118131
119- examples ! ( Day23 -> ( u32 , & ' static str ) [ ] ) ;
132+ examples ! ( Day23 -> ( u32 , & ' static str ) [
133+ { file: "day23_example0.txt" , part1: 7 , part2: "co,de,ka,ta" } ,
134+ ] ) ;
0 commit comments