day(05): solve part 2

Signed-off-by: Matej Focko <me@mfocko.xyz>
This commit is contained in:
Matej Focko 2024-12-05 15:10:10 +01:00
parent 2632bc7a58
commit ab88740e69
Signed by: mfocko
SSH key fingerprint: SHA256:icm0fIOSJUpy5+1x23sfr+hLtF9UhY8VpMC7H4WFJP8

View file

@ -5,6 +5,9 @@ class Day05(
private val updates: List<List<Int>> private val updates: List<List<Int>>
companion object { companion object {
val UNVISITED = 0
val OPEN = 1
val DONE = 2
} }
init { init {
@ -17,26 +20,61 @@ class Day05(
.map { line -> .map { line ->
line.split("|").map(String::toInt).let { it[0] to it[1] } line.split("|").map(String::toInt).let { it[0] to it[1] }
}.forEach { (before, after) -> }.forEach { (before, after) ->
getOrPut(after) { mutableSetOf() }.add(before) getOrPut(before) { mutableSetOf() }.add(after)
} }
} }
this.updates = updates.lineSequence().map { line -> line.split(",").map(String::toInt).toList() }.toList() this.updates = updates.lineSequence().map { line -> line.split(",").map(String::toInt).toList() }.toList()
} }
private fun printGraph() {
println("digraph G {")
rules.forEach { u, vs ->
vs.forEach { v ->
println("\t$u -> $v")
}
}
println("}")
}
override fun precompute() { override fun precompute() {
// no-op // no-op
} }
private fun isCorrect(update: List<Int>): Boolean = private fun isCorrect(update: List<Int>): Boolean =
update.withIndex().reversed().all { p -> update.withIndex().all { p ->
rules.getOrDefault(p.value, mutableSetOf()).all { preceding -> update.lastIndexOf(preceding) < p.index } rules
.getOrDefault(p.value, mutableSetOf())
.all { succeeding -> update.indexOf(succeeding).let { it == -1 || it > p.index } }
} }
override fun part1(): Int = updates.filter(::isCorrect).sumOf { it[it.size / 2] } override fun part1(): Int = updates.filter(::isCorrect).sumOf { it[it.size / 2] }
private fun fix(update: List<Int>): List<Int> = update // Toposort
private fun fix(xs: Set<Int>): List<Int> {
val ordering = mutableListOf<Int>()
val state = mutableMapOf<Int, Int>()
override fun part2(): Int = updates.filter { !isCorrect(it) }.map { fix(it) }.sumOf { it[it.size / 2] } fun visit(u: Int) {
if (state.getOrDefault(u, UNVISITED) == DONE) {
return
}
check(state.getOrDefault(u, UNVISITED) != OPEN) { "We have found a loop ending in $u" }
state[u] = OPEN
// .intersect(): Recursively search only the interesting successors
rules.getOrDefault(u, emptySet()).intersect(xs).forEach { visit(it) }
state[u] = DONE
ordering.add(u)
}
xs.forEach { visit(it) }
return ordering
}
override fun part2(): Int = updates.filter { !isCorrect(it) }.map { fix(it.toSet()) }.sumOf { it[it.size / 2] }
} }
fun main() { fun main() {