-
Notifications
You must be signed in to change notification settings - Fork 0
/
day25.lua
212 lines (177 loc) · 4.74 KB
/
day25.lua
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
require 'util'
DAY = 25 -- We made it!
local filename = string.format("inputs/input_%02d.txt", DAY)
local f = assert(io.open(filename, "r"))
-- Function definitions here
local graph = {} -- An adjacency list
local graphSize = 0
-- Remvoes the edge from a to b in the graph g
local function rmEdge(g, a, b)
for i, e in ipairs(g[a]) do
if e == b then
table.remove(g[a], i)
break
end
end
for i, e in ipairs(g[b]) do
if e == a then
table.remove(g[b], i)
break
end
end
end
-- Not used but I'm leaving here for comopleteness
local function addEdge(g, a, b)
table.insert(g[a], b)
table.insert(g[b], a)
end
-- The number of nodes in the graph
local function size(g)
local r = 0
for _, _ in pairs(g) do r = r + 1 end
return r
end
-- Returns a copy of the graph with the edge ab having been contracted (node a is kept)
local function edgeContract(graph, a, b)
local g = { [a] = {} }
for node, edges in pairs(graph) do
if node == b then
-- Add all the edges to a
for i, e in ipairs(edges) do
if e ~= a then
table.insert(g[a], e)
end
end
elseif node == a then
for i, e in ipairs(edges) do
if e ~= b then
table.insert(g[a], e)
end
end
else
if not g[node] then g[node] = {} end
for i, e in ipairs(edges) do
if e == b then
table.insert(g[node], a)
else
table.insert(g[node], e)
end
end
end
end
return g
end
-- Returns a random edge from a graph of size s
local function randEdge(g, s)
local r = math.random(s)
local i = 1
for n, edges in pairs(g) do
if i == r then
local n1 = n
local n2 = edges[math.random(#edges)]
return { n1, n2 }
end
i = i + 1
end
end
-- Returns a set of all of the edges in graph g
local function allEdges(g)
local r = {}
for n, edges in pairs(g) do
for i, v in ipairs(edges) do
r[n..","..v] = true
end
end
return r
end
local function contract(graph)
-- Doing kargers
local curG = graph
local s = size(curG)
local removedEdges = {}
local merges = {}
while s > 2 do
local e = randEdge(curG, s)
curG = edgeContract(curG, e[1], e[2])
s = size(curG)
-- Here I want to find the edges that were removed
local grp1 = merges[e[1]] or {[e[1]]=true}
local grp2 = merges[e[2]] or {[e[2]]=true}
-- Mark the edges as removed
for n1, _ in pairs(grp1) do
for n2, _ in pairs(grp2) do
removedEdges[#removedEdges+1] = {n1, n2}
removedEdges[#removedEdges+1] = {n2, n1}
end
end
-- Combine the groups
for k, v in pairs(grp2) do
grp1[k] = true
end
merges[e[2]] = nil
merges[e[1]] = grp1
end
-- We're left with a graph with two vertices
-- Get the size of the cut
local res1, res2
for k, v in pairs(curG) do
res1 = k
res2 = #v
break
end
return res1, res2, removedEdges
end
local function getGroupSize(g, s)
local visited = {[s] = true} -- Visited nodes
local q = { s }
local count = 0
while #q ~= 0 do
local cur = table.remove(q, 1)
count = count + 1
for i, v in ipairs(g[cur]) do
if not visited[v] then
visited[v] = true
q[#q + 1] = v
end
end
end
return count
end
for line in f:lines() do
-- Process the file here
local node, edges = line:match("(...): (.+)")
if not graph[node] then
graph[node] = {}
graphSize = graphSize + 1
end
for e in split(edges, " ") do
if not graph[e] then
graph[e] = {}
graphSize = graphSize + 1
end
table.insert(graph[node], e)
table.insert(graph[e], node)
end
end
-- Do everything else here
local part1 = 0
local part2 = "snow!"
while true do
local a, b, rmEdges = contract(graph)
if b == 3 then
local all = allEdges(graph)
for i, v in ipairs(rmEdges) do
all[v[1]..","..v[2]] = nil
all[v[2]..","..v[1]] = nil
end
for k, v in pairs(all) do
local x, y = k:match("(...),(...)")
rmEdge(graph, x, y)
end
local grpSize = getGroupSize(graph, a)
part1 = (graphSize - grpSize) * grpSize
break
end
end
print("Part 1:", part1)
print("Part 2:", part2)