-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathday_25.ex
79 lines (67 loc) · 2.02 KB
/
day_25.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
defmodule AdventOfCode.Y2023.Day25 do
@moduledoc """
--- Day 25: Snowverload ---
Problem Link: https://adventofcode.com/2023/day/25
Difficulty: xl
Tags: graph min-cut probabilistic refactor not-fast-enough
"""
alias AdventOfCode.Helpers.{InputReader, Transformers}
def input, do: InputReader.read_from_file(2023, 25)
def run(input \\ input()) do
input = parse(input)
{run_1(input), run_2(input)}
end
defp run_1(input) do
Stream.repeatedly(fn -> contract(input) end)
|> Enum.find(fn g1 -> cut_size(g1, input) == 3 end)
|> Map.keys()
|> Enum.map(&String.length/1)
|> Enum.product_by(&div(&1, 3))
end
defp run_2(_), do: "🎉"
def parse(input) do
for line <- Transformers.lines(input), reduce: %{} do
graph ->
[u | connected] = String.split(line, [":", " "], trim: true)
for v <- connected, reduce: graph do
edges ->
edges
|> Map.update(u, MapSet.new([v]), &MapSet.put(&1, v))
|> Map.update(v, MapSet.new([u]), &MapSet.put(&1, u))
end
end
end
def cut_size(g, h) do
for {key, _} <- g do
key
|> String.to_charlist()
|> Enum.chunk_every(3)
|> Enum.map(&to_string/1)
end
|> then(fn [us, vs] ->
for u <- us, _ <- MapSet.intersection(h[u], MapSet.new(vs)), reduce: 0 do
acc -> acc + 1
end
end)
end
def contract(graph) when map_size(graph) == 2, do: graph
def contract(graph) do
{u, u_edges} = Enum.random(graph)
v = Enum.random(u_edges)
u_edges = u_edges |> MapSet.delete(v)
v_edges = graph[v] |> MapSet.delete(u)
u_v_edges = MapSet.union(u_edges, v_edges)
uv = u <> v
Enum.reduce(u_edges, graph, fn c, acc ->
Map.update!(acc, c, &MapSet.put(MapSet.delete(&1, u), uv))
end)
|> then(fn graph ->
Enum.reduce(v_edges, graph, fn c, acc ->
Map.update!(acc, c, &MapSet.put(MapSet.delete(&1, v), uv))
end)
|> Map.drop([u, v])
|> Map.put(uv, u_v_edges)
end)
|> contract()
end
end