11use crate :: puzzle:: Puzzle ;
2+ use std:: collections:: BinaryHeap ;
23
34pub struct Day {
45 points : Vec < Point > ,
@@ -8,34 +9,52 @@ impl Puzzle for Day {
89 /// Connect the 1000 closest pairs, then multiply sizes of the 3 largest circuits.
910 ///
1011 /// Time complexity: O(N^2)
11- /// Auxiliary space complexity: O(N^2 )
12+ /// Auxiliary space complexity: O(N)
1213 fn solve_part_1 ( & self ) -> String {
1314 short_connections_product ( & self . points , 1000 ) . to_string ( )
1415 }
1516
1617 /// Keep connecting closest pairs until all junction boxes are in one circuit.
1718 /// Return product of X coordinates of the last edge that merges the final two components.
1819 ///
19- /// Time complexity: O(N^2 log N )
20- /// Auxiliary space complexity: O(N^2 )
20+ /// Time complexity: O(N^2)
21+ /// Auxiliary space complexity: O(N)
2122 fn solve_part_2 ( & self ) -> String {
2223 let n = self . points . len ( ) ;
23- let mut edges = all_edges ( & self . points ) ;
24- edges. sort_unstable_by_key ( |e| e. dist2 ) ;
25- let mut dsu = Dsu :: new ( n) ;
26- let mut last_merged: Option < Edge > = None ;
27- for e in edges {
28- if dsu. union ( e. from , e. to ) {
29- last_merged = Some ( e) ;
30- if dsu. components == 1 {
31- break ;
24+ let mut in_mst = vec ! [ false ; n] ;
25+ let mut best = vec ! [ u64 :: MAX ; n] ;
26+ let mut parent: Vec < Option < usize > > = vec ! [ None ; n] ;
27+ let mut max_edge: Option < ( u64 , usize ) > = None ;
28+ best[ 0 ] = 0 ;
29+ for _ in 0 ..n {
30+ let v = ( 0 ..n)
31+ . filter ( |& i| !in_mst[ i] )
32+ . min_by_key ( |& i| best[ i] )
33+ . unwrap ( ) ;
34+ let v_best = best[ v] ;
35+ in_mst[ v] = true ;
36+ if parent[ v] . is_some ( ) {
37+ match max_edge {
38+ None => max_edge = Some ( ( v_best, v) ) ,
39+ Some ( ( d, _) ) if v_best > d => max_edge = Some ( ( v_best, v) ) ,
40+ _ => { }
41+ }
42+ }
43+ for u in 0 ..n {
44+ if !in_mst[ u] {
45+ let d = self . points [ v] . dist2 ( & self . points [ u] ) ;
46+ if d < best[ u] {
47+ best[ u] = d;
48+ parent[ u] = Some ( v) ;
49+ }
3250 }
3351 }
3452 }
35- let e = last_merged. unwrap ( ) ;
36- let p1_x = self . points [ e. from ] . x ;
37- let p2_x = self . points [ e. to ] . x ;
38- ( p1_x * p2_x) . to_string ( )
53+ let ( _, v) = max_edge. unwrap ( ) ;
54+ let p = parent[ v] . unwrap ( ) ;
55+ let a = self . points [ v] . x as i128 ;
56+ let b = self . points [ p] . x as i128 ;
57+ ( a * b) . to_string ( )
3958 }
4059}
4160
@@ -72,26 +91,25 @@ impl Point {
7291 }
7392}
7493
94+ #[ derive( Eq , PartialEq ) ]
7595struct Edge {
7696 from : usize ,
7797 to : usize ,
7898 dist2 : u64 ,
7999}
80100
81- fn all_edges ( points : & [ Point ] ) -> Vec < Edge > {
82- let n = points. len ( ) ;
83- let mut edges = Vec :: with_capacity ( n * ( n - 1 ) / 2 ) ;
84- for i in 0 ..n {
85- for j in ( i + 1 ) ..n {
86- let dist2 = points[ i] . dist2 ( & points[ j] ) ;
87- edges. push ( Edge {
88- from : i,
89- to : j,
90- dist2,
91- } ) ;
92- }
101+ impl Ord for Edge {
102+ fn cmp ( & self , other : & Self ) -> std:: cmp:: Ordering {
103+ self . dist2
104+ . cmp ( & other. dist2 )
105+ . then_with ( || self . from . cmp ( & other. from ) )
106+ . then_with ( || self . to . cmp ( & other. to ) )
107+ }
108+ }
109+ impl PartialOrd for Edge {
110+ fn partial_cmp ( & self , other : & Self ) -> Option < std:: cmp:: Ordering > {
111+ Some ( self . cmp ( other) )
93112 }
94- edges
95113}
96114
97115struct Dsu {
@@ -154,16 +172,35 @@ impl Dsu {
154172
155173fn short_connections_product ( points : & [ Point ] , count : usize ) -> usize {
156174 let n = points. len ( ) ;
157- let mut edges = all_edges ( points) ;
158- let k = count. min ( edges. len ( ) ) ;
159- edges. select_nth_unstable_by_key ( k - 1 , |e| e. dist2 ) ;
160- edges. truncate ( k) ;
175+ let mut edges: BinaryHeap < Edge > = BinaryHeap :: with_capacity ( count + 1 ) ;
176+ for i in 0 ..n {
177+ for j in ( i + 1 ) ..n {
178+ let d = points[ i] . dist2 ( & points[ j] ) ;
179+ if edges. len ( ) < count {
180+ edges. push ( Edge {
181+ from : i,
182+ to : j,
183+ dist2 : d,
184+ } ) ;
185+ } else if let Some ( top) = edges. peek ( ) {
186+ if d < top. dist2 {
187+ edges. pop ( ) ;
188+ edges. push ( Edge {
189+ from : i,
190+ to : j,
191+ dist2 : d,
192+ } ) ;
193+ }
194+ }
195+ }
196+ }
161197 let mut dsu = Dsu :: new ( n) ;
162198 for e in edges {
163199 dsu. union ( e. from , e. to ) ;
164200 }
165201 let mut sizes = dsu. component_sizes ( ) ;
166- sizes. sort_unstable_by ( |a, b| b. cmp ( a) ) ;
202+ sizes. select_nth_unstable_by_key ( 2 , |& x| std:: cmp:: Reverse ( x) ) ;
203+ sizes. truncate ( 3 ) ;
167204 sizes. into_iter ( ) . take ( 3 ) . product ( )
168205}
169206
0 commit comments