2024 day 23 some further tidy-ups.
This commit is contained in:
100
bin/day2423.ml
100
bin/day2423.ml
@@ -20,37 +20,27 @@ let load_file fname =
|
||||
|> List.map make_pairs
|
||||
|> List.fold_left add_connection StringMap.empty
|
||||
|
||||
let is_three_ring connections a _ candidate =
|
||||
StringSet.mem candidate (StringMap.find a connections)
|
||||
|
||||
let rec find_third_member acc connections visited a b candidates =
|
||||
match candidates with
|
||||
| [] -> acc
|
||||
| h :: t ->
|
||||
if StringSet.mem h visited then
|
||||
find_third_member acc connections visited a b t
|
||||
else if not (is_three_ring connections a b h) then
|
||||
find_third_member acc connections visited a b t
|
||||
else
|
||||
let acc = StringSet.of_list [ a; b; h ] :: acc in
|
||||
find_third_member acc connections visited a b t
|
||||
|
||||
let rec find_second_member acc connections visited a candidates =
|
||||
match candidates with
|
||||
let rec find_second_member acc connections visited a =
|
||||
let rec impl acc a b = function
|
||||
| [] -> acc
|
||||
| c :: t -> impl (StringSet.of_list [ a; b; c ] :: acc) a b t
|
||||
in
|
||||
function
|
||||
| [] -> acc
|
||||
| h :: t ->
|
||||
if StringSet.mem h visited then
|
||||
find_second_member acc connections visited a t
|
||||
else
|
||||
let visited = StringSet.add h visited in
|
||||
let acc =
|
||||
find_third_member acc connections visited a h
|
||||
(StringSet.to_list (StringMap.find h connections))
|
||||
let anh =
|
||||
StringSet.inter
|
||||
(StringMap.find a connections)
|
||||
(StringMap.find h connections)
|
||||
in
|
||||
let acc = impl acc a h (StringSet.to_list anh) in
|
||||
find_second_member acc connections visited a t
|
||||
|
||||
let rec find_rings acc visited connections computers =
|
||||
match computers with
|
||||
let rec find_rings acc visited connections = function
|
||||
| [] -> acc
|
||||
| h :: t ->
|
||||
if StringSet.mem h visited then find_rings acc visited connections t
|
||||
@@ -62,38 +52,60 @@ let rec find_rings acc visited connections computers =
|
||||
in
|
||||
find_rings acc visited connections t
|
||||
|
||||
(** [starts_with_t set] returns true if any member of [set] starts with the
|
||||
letter ['t']. *)
|
||||
let starts_with_t set = StringSet.exists (fun x -> x.[0] = 't') set
|
||||
|
||||
let set_compare a b = compare (StringSet.elements a) (StringSet.elements b)
|
||||
|
||||
let part1 connections =
|
||||
let computers = StringMap.to_list connections |> List.map fst in
|
||||
let rings =
|
||||
find_rings [] StringSet.empty connections computers
|
||||
|> List.filter starts_with_t
|
||||
in
|
||||
string_of_int (List.length rings)
|
||||
StringMap.to_list connections
|
||||
|> List.map fst
|
||||
|> find_rings [] StringSet.empty connections
|
||||
|> List.filter starts_with_t |> List.sort_uniq set_compare |> List.length
|
||||
|> string_of_int
|
||||
|
||||
let rec search_candidate max_set connections current candidates =
|
||||
match StringSet.choose_opt candidates with
|
||||
| None ->
|
||||
if List.length current > List.length max_set then current else max_set
|
||||
| Some h ->
|
||||
(** [search_candidate max_lst connections current candidates] searches for the
|
||||
longest star network that contains all the computers in [current] and maybe
|
||||
some of the elements of [candidates].
|
||||
|
||||
[max_lst] is the biggest network found so far. [connections] is the map of
|
||||
computers to direct connections.
|
||||
|
||||
The initial call should look something like:
|
||||
|
||||
[search_candidate [] connections k (StringSet.to_list (StringMap.find k
|
||||
connections))] *)
|
||||
let rec search_candidate max_lst connections current candidates =
|
||||
match candidates with
|
||||
| [] -> if List.length current > List.length max_lst then current else max_lst
|
||||
| h :: t ->
|
||||
let map = StringMap.find h connections in
|
||||
let current' = h :: current in
|
||||
let candidates' =
|
||||
StringSet.inter candidates (StringMap.find h connections)
|
||||
in
|
||||
let max_set = search_candidate max_set connections current' candidates' in
|
||||
search_candidate max_set connections current
|
||||
(StringSet.remove h candidates)
|
||||
let candidates' = List.filter (Fun.flip StringSet.mem map) candidates in
|
||||
let max_lst = search_candidate max_lst connections current' candidates' in
|
||||
search_candidate max_lst connections current t
|
||||
|
||||
(** [find_max_set connections] returns a list containing the largest number of
|
||||
computers in a star network (that is for every pair of elements in the list
|
||||
there is a connection between them).
|
||||
|
||||
[connections] is the map of connections keyed by computer with the value
|
||||
being a set of all direct connections. [connections] must be bi-directional
|
||||
that is if: [StringSet.mem a (StringMap.find b connections)] then
|
||||
[StringSet.mem b (StringMap.find a connections)]. Note that
|
||||
[StringSet.mem a (StringMap.find a connections)] must return [false]. *)
|
||||
let find_max_set connections =
|
||||
let rec impl max_set = function
|
||||
| [] -> max_set
|
||||
| (k, v) :: t -> impl (search_candidate max_set connections [ k ] v) t
|
||||
let rec impl max_lst = function
|
||||
| [] -> max_lst
|
||||
| (k, v) :: t ->
|
||||
impl
|
||||
(search_candidate max_lst connections [ k ] (StringSet.to_list v))
|
||||
t
|
||||
in
|
||||
impl [] (StringMap.to_list connections)
|
||||
|
||||
let part2 connections =
|
||||
let max_set = find_max_set connections in
|
||||
List.sort compare max_set |> String.concat ","
|
||||
find_max_set connections |> List.sort compare |> String.concat ","
|
||||
|
||||
let _ = Aoc.main load_file [ (Fun.id, part1); (Fun.id, part2) ]
|
||||
|
Reference in New Issue
Block a user