Use binary search for 2024 day 18 part 2.

This dramatically speeds the search up (by ~100x).
This commit is contained in:
2024-12-18 10:30:43 +00:00
parent fe94d8b371
commit 4eb967fd88

View File

@@ -110,12 +110,31 @@ let part1 count rocks =
[grid] which makes it impossible to get from the top-left to bottom-right. [grid] which makes it impossible to get from the top-left to bottom-right.
*) *)
let part2 start_count grid = let part2 start_count grid =
let rec impl count = (* Implementation notes:
match find_route_length count grid with
| None -> count We do this by binary search in impl. The left_count is a known count of
| Some _ -> impl (count + 1) rocks that is passable, right_count is a known count that is impassable.
Once left_count + 1 = right_count we know that right_count is the first
rock to fall that causes the route to be blocked.
count_rocks is used to find the number of rocks (and so give an initial
right_count).
*)
let rec count_rocks acc idx =
if idx >= Array.length grid.grid then acc
else if grid.grid.(idx) = max_int then count_rocks acc (idx + 1)
else count_rocks (max acc grid.grid.(idx)) (idx + 1)
in in
let count = impl start_count in let rec impl left_count right_count =
if right_count - left_count = 1 then right_count
else
let count = (left_count + right_count) / 2 in
match find_route_length count grid with
| None -> impl left_count count
| Some _ -> impl count right_count
in
let count = impl start_count (1 + count_rocks 0 0) in
match Array.find_index (( = ) (count - 1)) grid.grid with match Array.find_index (( = ) (count - 1)) grid.grid with
| None -> failwith "part2" | None -> failwith "part2"
| Some idx -> idx | Some idx -> idx