Uknow's Lab.
article thumbnail

https://www.acmicpc.net/problem/4386

 

4386번: 별자리 만들기

도현이는 우주의 신이다. 이제 도현이는 아무렇게나 널브러져 있는 n개의 별들을 이어서 별자리를 하나 만들 것이다. 별자리의 조건은 다음과 같다. 별자리를 이루는 선은 서로 다른 두 별을 일

www.acmicpc.net

 

난이도 : 골드 3
태그 : 그래프 이론, 최소 스패닝 트리

 

 

설명

모든 별을 선으로 이어 별자리를 만드는 문제입니다.

별자리를 잇는다는 건, 두 별을 직선으로 이은 것이며, 모든 별자리는 직/간접적으로 서로 이어져 있어야 합니다.

별을 이을 때 거리만큼의 비용이 들 때, 모든 별을 직/간접적으로 이으면서 그 비용이 최소가 되는 경우를 찾아야 합니다.

 

"모든 별(노드)를 선으로 직/간접적으로 이으면서, 그 비용이 최소가 된다"라는 점에서, 최소 스패닝 트리 문제임을 알 수 있습니다.

최소 스패닝 트리에 대해 잘 모르겠다면 아래 포스팅을 참고해주세요.

https://uknowblog.tistory.com/294

 

[알고리즘] 최소 스패닝 트리 (MST, Minimum Spanning Tree)

최소 스패닝 트리 / 최소 신장 트리 (MST, Minimun Spanning Tree) 스패닝 트리 / 신장 트리는 모든 정점(Vertex, Node)을 간선(Edge)로 사이클이 생기지 않게 연결한 그래프입니다. 최소 스패닝 트리 / 최소 신

uknowblog.tistory.com

 

 

다행이도 별들은 이차원 평면 위에 놓여져 있습니다.

즉, 두 별을 직선으로 이었을 때 거리는 피타고라스로 쉽게 구할 수 있습니다.

 

다른 최소 스패닝 트리에서는 노드와 연결된 간선도 주어지지만,

이 문제에서는 노드와 그 좌표만 주어질 뿐, 간선의 정보는 주어지지 않습니다.

따라서 저는 그냥 n개의 별 중 2개의 별을 이은 모든 간선을 만들어준 뒤,

크루스칼 알고리즘과 유니온 파인드를 사용해 풀이하였습니다.

 

 

 

 

소스코드

import java.util.PriorityQueue
import kotlin.math.pow
import kotlin.math.sqrt

data class Node(val from: Int, val to: Int, val weight: Double) : Comparable<Node> {
    override fun compareTo(other: Node): Int {
        return if(this.weight > other.weight) 1 else -1
    }
}

data class Star(var x: Double, var y: Double)

var total = 0.0
lateinit var parent: Array<Int>

fun main() {
    val n = readLine()!!.toInt()
    parent = Array(n + 1) { it }

    val stars = Array<Star>(n) { Star(0.0, 0.0) }

    val pq = PriorityQueue<Node>()

    for (i in 0 until n) {
        val line = readLine()!!.split(" ")
        stars[i].x = line[0].toDouble()
        stars[i].y = line[1].toDouble()

        for (j in 0 until i) {
            val weight = sqrt((stars[i].x - stars[j].x).pow(2) + (stars[i].y - stars[j].y).pow(2))
            pq.add(Node(i, j, weight))
        }
    }

    while(pq.isNotEmpty()) {
        val node = pq.poll()

        if (find(node.from) != find(node.to)) {
            total += node.weight
            union(node.from, node.to)
        }
    }

    println(total)
}

fun find(x: Int): Int {
    return if (parent[x] == x) x
    else {
        parent[x] = find(parent[x])
        parent[x]
    }
}

fun union(x: Int, y: Int) {
    val nx = find(x)
    val ny = find(y)
    if (nx != ny) {
        if(x < y) {
            parent[ny] = nx
        } else {
            parent[nx] = ny
        }
    }
}

 

 

 

후기

별들을 이어 별자리를 만든다는 낭만적인 문제였습니다.

profile

Uknow's Lab.

@유노 Uknow

인생은 Byte와 Double 사이 Char다. 아무말이나 해봤습니다.