@@ -3,77 +3,53 @@ defmodule AdventOfCode.Y2023.Day25 do
33 --- Day 25: Snowverload ---
44 Problem Link: https://adventofcode.com/2023/day/25
55 Difficulty: xl
6- Tags: graph min-cut probabilistic refactor not-fast-enough
6+ Tags: graph min-cut deterministic refactor
77 """
88 alias AdventOfCode.Helpers . { InputReader , Transformers }
9+ alias Yog.Builder.Labeled
10+ alias Yog.Flow.MinCut
11+ alias Yog.Flow.MinCutResult
912
1013 def input , do: InputReader . read_from_file ( 2023 , 25 )
1114
1215 def run ( input \\ input ( ) ) do
13- input = parse ( input )
16+ builder = parse ( input )
17+ graph = Labeled . to_graph ( builder )
1418
15- { run_1 ( input ) , run_2 ( input ) }
19+ { run_1 ( graph ) , run_2 ( graph ) }
1620 end
1721
18- defp run_1 ( input ) do
19- Stream . repeatedly ( fn -> contract ( input ) end )
20- |> Enum . find ( fn g1 -> cut_size ( g1 , input ) == 3 end )
21- |> Map . keys ( )
22- |> Enum . map ( & String . length / 1 )
23- |> Enum . product_by ( & div ( & 1 , 3 ) )
22+ defp run_1 ( graph ) do
23+ # Stoer-Wagner finds the global minimum cut in an undirected graph.
24+ # In this problem, we are guaranteed that the global min-cut size is 3.
25+ result = MinCut . global_min_cut ( graph )
26+
27+ # Use the optimized partition_product helper
28+ MinCutResult . partition_product ( result )
2429 end
2530
2631 defp run_2 ( _ ) , do: "🎉"
2732
33+ @ doc """
34+ Parses the input into a Yog Labeled builder.
35+ Each line defines a node and its connections: `jqt: rhn xhk nvd`
36+ """
2837 def parse ( input ) do
29- for line <- Transformers . lines ( input ) , reduce: % { } do
30- graph ->
31- [ u | connected ] = String . split ( line , [ ":" , " " ] , trim: true )
32-
33- for v <- connected , reduce: graph do
34- edges ->
35- edges
36- |> Map . update ( u , MapSet . new ( [ v ] ) , & MapSet . put ( & 1 , v ) )
37- |> Map . update ( v , MapSet . new ( [ u ] ) , & MapSet . put ( & 1 , u ) )
38- end
39- end
40- end
41-
42- def cut_size ( g , h ) do
43- for { key , _ } <- g do
44- key
45- |> String . to_charlist ( )
46- |> Enum . chunk_every ( 3 )
47- |> Enum . map ( & to_string / 1 )
48- end
49- |> then ( fn [ us , vs ] ->
50- for u <- us , _ <- MapSet . intersection ( h [ u ] , MapSet . new ( vs ) ) , reduce: 0 do
51- acc -> acc + 1
38+ data = Transformers . lines ( input )
39+
40+ Enum . reduce ( data , Labeled . undirected ( ) , fn line , builder ->
41+ case String . split ( line , ": " , trim: true ) do
42+ [ source , dests ] ->
43+ dests
44+ |> String . split ( " " , trim: true )
45+ |> Enum . reduce ( builder , fn target , b ->
46+ Labeled . add_edge ( b , source , target , 1 )
47+ end )
48+
49+ _ ->
50+ builder
5251 end
5352 end )
5453 end
55-
56- def contract ( graph ) when map_size ( graph ) == 2 , do: graph
57-
58- def contract ( graph ) do
59- { u , u_edges } = Enum . random ( graph )
60- v = Enum . random ( u_edges )
61-
62- u_edges = u_edges |> MapSet . delete ( v )
63- v_edges = graph [ v ] |> MapSet . delete ( u )
64- u_v_edges = MapSet . union ( u_edges , v_edges )
65- uv = u <> v
66-
67- Enum . reduce ( u_edges , graph , fn c , acc ->
68- Map . update! ( acc , c , & MapSet . put ( MapSet . delete ( & 1 , u ) , uv ) )
69- end )
70- |> then ( fn graph ->
71- Enum . reduce ( v_edges , graph , fn c , acc ->
72- Map . update! ( acc , c , & MapSet . put ( MapSet . delete ( & 1 , v ) , uv ) )
73- end )
74- |> Map . drop ( [ u , v ] )
75- |> Map . put ( uv , u_v_edges )
76- end )
77- |> contract ( )
78- end
7954end
55+
0 commit comments