Skip to content

Commit 878a758

Browse files
committed
Solve 2023/25
1 parent 82c3ee3 commit 878a758

3 files changed

Lines changed: 34 additions & 58 deletions

File tree

lib/2023/day_25.ex

Lines changed: 32 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -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
7954
end
55+

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ defmodule AdventOfCode.MixProject do
2626
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
2727
{:floki, "~> 0.36"},
2828
{:httpoison, "~> 2.2"},
29-
{:yog_ex, "~> 0.90.0"},
29+
{:yog_ex, github: "code-shoily/yog_ex", branch: "main"},
3030
{:aja, "~> 0.7"},
3131
{:topo, "~> 1.0"},
3232
{:rustler, "~> 0.35"}

mix.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@
2020
"topo": {:hex, :topo, "1.0.3", "8073215c392ad0aced6505a5a281da4af613f5608f6db826635b96fe7a2f4240", [:mix], [{:geo, "~> 3.1 or ~> 4.0", [hex: :geo, repo: "hexpm", optional: false]}, {:seg_seg, "~> 1.0", [hex: :seg_seg, repo: "hexpm", optional: false]}, {:vector, "~> 1.0", [hex: :vector, repo: "hexpm", optional: false]}], "hexpm", "d37720895ec08848d33960deb94f00254834e0a2398618461b800f142c84577c"},
2121
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.1", "a48703a25c170eedadca83b11e88985af08d35f37c6f664d6dcfb106a97782fc", [:rebar3], [], "hexpm", "b3a917854ce3ae233619744ad1e0102e05673136776fb2fa76234f3e03b23642"},
2222
"vector": {:hex, :vector, "1.1.0", "0789b5e00e9c551d8d5880acab9a8f44ed46690d083af397018bf0c7f30c1092", [:mix], [], "hexpm", "48b0a800ec88e55b12c689b09100e4c9ba41ea1befb459221c085a4e70040696"},
23-
"yog_ex": {:hex, :yog_ex, "0.90.0", "07c66979ff547faea560f1a40c4613071cd491651a0b5a1d81d75cef13388153", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:saxy, "~> 1.5", [hex: :saxy, repo: "hexpm", optional: false]}], "hexpm", "9d90a291fe40a535b525003a831347808f8a1120ced64409210f7efef1c172b3"},
23+
"yog_ex": {:git, "https://github.com/code-shoily/yog_ex.git", "74dd8f69469cb4cb2fe2c197181b2c3d2188b2f3", [branch: "main"]},
2424
}

0 commit comments

Comments
 (0)