/** * So lets try something else again. This is the closest pair problem in a 3d grid, described as a rare problem in CP4. * I would have like to implement it with a randomized algorithm, but using divide and conquer is faster to implement. */ import kotlin.math.pow import kotlin.math.sqrt fun main() { val reader = System.`in`.bufferedReader() val n = reader.readLine().toInt() val input = reader.lineSequence().take(n).map { string -> string.split(" ", limit = 3) .map { it.toDouble() } .let { (x, y, z) -> Coordinate(x, y, z) } }.sortedWith { o1, o2 -> o1.compareTo(o2) }.toList() println(input.conquer()) } fun List.divide() = take(size / 2) to drop(size / 2) fun List.conquer(): Double = when (size) { 1 -> Double.MAX_VALUE 2 -> first().distance(last()) else -> { val (left, right) = divide() //min distance is either left or right val d = left.conquer().coerceAtMost(right.conquer()) // or a combination of left and right with a max distance of d from the middle // (for 2d this is max 6 points, I guess for 3d a similar low number holds, so this should be O(log n)) val division = right.first() - left.last() val leftCutOff = division - d val rightCutOff = division + d val overlap = left.takeLastWhile { it >= leftCutOff } + right.takeWhile { it <= rightCutOff } when(overlap.size) { size -> (left.drop(1) + right.dropLast(1)).conquer().coerceAtMost(d) // nasty corner case, covered in example 1 0, 1 -> d else ->overlap.conquer().coerceAtMost(d) } } } private operator fun Coordinate.compareTo(o2: Coordinate) = when (first) { o2.first -> when (second) { o2.second -> third.compareTo(o2.third) else -> second.compareTo(o2.second) } else -> first.compareTo(o2.first) } typealias Coordinate = Triple operator fun Coordinate.minus(other: Coordinate) = Triple(first - other.first, second - other.second, third - other.third) operator fun Coordinate.plus(d: Double) = Triple(first + d, second + d, third + d) operator fun Coordinate.minus(d: Double) = Triple(first - d, second - d, third - d) inline fun Coordinate.distance(other: Coordinate) = sqrt((first - other.first).pow(2) + (second - other.second).pow(2) + (third - other.third).pow(2))