코딩테스트/백준 코틀린
[6개월 안에 백준 플래티넘 달성하기] 17. 도시 분할 계획 1197
junjunjun
2024. 1. 2. 14:22
반응형
문제
풀이
문제의 조건은 다음과 같습니다.
- 양방향이다.
- 마을을 두 개의 분리된 마을로 분할한다.
- 마을과 마을 사이에는 길이 존재하지 않는다.
- 마을 내부의 임의의 두 집 사이에는 경로가 항상 존재한다.
- 마을 내부에는 최소 하나 이상의 집이 있다.
- 위 조건을 만족하면서 유지비의 합이 최소여야 한다.
조건이 다소 많아 처음에는 흠칫하였지만 임의의 두 집 사이에는 경로가 항상 존재하며 최소 유지비를 만들어야 된다는 것에서 쉽게 최소 신장 트리 알고리즘을 생각할 수 있었습니다.
풀이 방법은 다음과 같습니다.
- 전체 집을 대상으로 최소 신장 트리를 구합니다. (= 경로 최소화 작업)
- 간선들 중에 가장 큰 유지비를 가진 가중치를 하나 제거해 줍니다.(= 마을 분리 작업)
위의 두 단계만으로 문제를 해결할 수 있습니다.
import java.io.StreamTokenizer
import java.util.PriorityQueue
fun main() = StreamTokenizer(System.`in`.bufferedReader()).run {
fun input(): Int {
nextToken()
return nval.toInt()
}
data class Node(val num: Int, var dist: Int) : Comparable<Node> {
override fun compareTo(other: Node): Int {
return if (dist <= other.dist) -1
else 1
}
}
val N = input() // 집의 개수
val M = input() // 길의 개수
val arr = Array(N+1) { arrayListOf<Node>() }
repeat(M) {
val a = input()
val b = input()
val c = input()
arr[a].add(Node(b, c))
arr[b].add(Node(a, c))
}
var result = 0 // 유지비
var maxValue = 0 // 마을 사이 최대 유지비
val pq = PriorityQueue<Node>()
val visited = BooleanArray(N+1)
pq.add(Node(1, 0))
// 최소 신장 트리
while (pq.isNotEmpty()) {
val cur = pq.poll()
if (visited[cur.num]) continue
visited[cur.num] = true
if (maxValue < cur.dist) maxValue = cur.dist // 최대 간선 갱신
result += cur.dist
for (next in arr[cur.num]) {
if (!visited[next.num]) {
pq.add(next)
}
}
}
// 최대 간선 빼줌
print(result - maxValue)
}
반응형