-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day25.kt
91 lines (72 loc) · 2.86 KB
/
Day25.kt
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
package io.dmitrijs.aoc2023
private typealias ComponentGraph = MutableMap<String, MutableSet<String>>
class Day25(private val input: List<String>) {
fun puzzle1(): Int {
val edges = input.flatMap { line ->
val v = line.substringBefore(": ")
line.substringAfter(": ").split(" ").map { u -> Edge(v, u) }
}
val nodes = (edges.map { it.v } + edges.map { it.u })
.toSet()
.withIndex()
.associate { (index, node) -> node to index }
do {
val (cutSize, dus) = kargerMinCut(nodes, edges)
if (cutSize == 3) {
val sets = mutableMapOf<Int, Int>()
nodes.forEach { (_, index) ->
val set = find(index, dus)
sets[set] = sets.getOrPut(set) { 0 }.inc()
}
require(sets.size == 2)
return sets.values.reduce { a, b -> a * b }
}
} while (true)
}
private fun kargerMinCut(nodes: Map<String, Int>, edges: List<Edge>): Pair<Int, IntArray> {
val parent = IntArray(nodes.size) { it }
val rank = IntArray(nodes.size)
fun findRoot(node: String) = find(nodes.getValue(node), parent)
val edgesLeft = edges.toMutableList()
var vertices = nodes.size
// Union-Find
while (vertices > 2) {
val edge = edgesLeft.random()
val setV = findRoot(edge.v)
val setU = findRoot(edge.u)
if (setU != setV) {
vertices--
union(setV, setU, parent, rank)
}
edgesLeft.remove(edge)
}
val cutSize = edgesLeft.count { findRoot(it.v) != findRoot(it.u) }
return cutSize to parent
}
private fun find(node: Int, parent: IntArray): Int {
if (node == parent[node]) return node
// With path compression
return find(parent[node], parent).also { parent[node] = it }
}
private fun union(vRoot: Int, uRoot: Int, parent: IntArray, rank: IntArray) = when {
rank[vRoot] < rank[uRoot] -> parent[vRoot] = uRoot
rank[vRoot] > rank[uRoot] -> parent[uRoot] = vRoot
else -> {
parent[vRoot] = uRoot
rank[uRoot] += 1
}
}
private data class Edge(val v: String, val u: String)
private fun dot(): Int {
val dot = input.joinToString(separator = "\n", prefix = "digraph {\n", postfix = "\n}") { line ->
val parts = line.split(": ", " ")
parts.drop(1).joinToString("\n") { node -> " ${parts[0]} -> $node" }
}
// 1) dot -T svg -K neato src/main/resources/day25.dot > src/main/resources/day25.svg
// 2) modify
// 3) ccomps -v src/main/resources/day25.modified.dot > foo.dot
// 4) see summary e.g. 756 nodes & 719 nodes
println(dot)
return 54
}
}