코딩테스트/백준

[백준 2887] 행성 터널 - 플래티넘5 / 최소 신장 트리

yejin72 2023. 2. 3. 18:27
728x90

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

 

2887번: 행성 터널

첫째 줄에 행성의 개수 N이 주어진다. (1 ≤ N ≤ 100,000) 다음 N개 줄에는 각 행성의 x, y, z좌표가 주어진다. 좌표는 -109보다 크거나 같고, 109보다 작거나 같은 정수이다. 한 위치에 행성이 두 개 이

www.acmicpc.net

문제

때는 2040년, 이민혁은 우주에 자신만의 왕국을 만들었다. 왕국은 N개의 행성으로 이루어져 있다. 민혁이는 이 행성을 효율적으로 지배하기 위해서 행성을 연결하는 터널을 만들려고 한다.

행성은 3차원 좌표 위의 한 점으로 생각하면 된다. 두 행성 A(xA, yA, zA)와 B(xB, yB, zB)를 터널로 연결할 때 드는 비용은 min(|xA-xB|, |yA-yB|, |zA-zB|)이다.

민혁이는 터널을 총 N-1개 건설해서 모든 행성이 서로 연결되게 하려고 한다. 이때, 모든 행성을 터널로 연결하는데 필요한 최소 비용을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 행성의 개수 N이 주어진다. (1 ≤ N ≤ 100,000) 다음 N개 줄에는 각 행성의 x, y, z좌표가 주어진다. 좌표는 -109보다 크거나 같고, 109보다 작거나 같은 정수이다. 한 위치에 행성이 두 개 이상 있는 경우는 없다. 

출력

첫째 줄에 모든 행성을 터널로 연결하는데 필요한 최소 비용을 출력한다.

 

 


이 문제에서 주어지는 행성의 수는 최대 100,000개이다.

간선의 수는 N*(N-1)/2 개이고, 이는 너무 많은 개수로 인해 평소 크루스칼 알고리즘을 사용하면 메모리 초과가 일어난다.

 

 

문제에 따르면, 두 행성 간의 터널을 만드는 비용은 각 x, y, z 좌표를 뺀 것의 절댓값 중 작은 것이다.

만들어지는 간선을 수를 줄이기 위해서는 최대한 서로의 위치가 가까운 행성 간의 비용만을 구해야 한다. 이게 무엇이냐하면 x, y, z 세 좌표들을 각각의 길이별로 오름차순 정렬했을 때, 바로 옆에 위치한 두 행성들끼리 터널을 만드는 것이 비용이 가장 적다는 것이다.

 

기존 방법대로 간선을 모두 탐색하다 보면 O(n^2)의 시간이 걸리지만, 새로운 방법대로 진행한다면 O(3n), 즉 O(n)의 시간복잡도까지 줄일 수 있다!

 

 

<< 전체 코드 >>

import sys
input = sys.stdin.readline

answer = 0
n = int(input())
root = [i for i in range(n)]

planets = []
for i in range(n):
    x, y, z = map(int, input().split())
    planets.append((x, y, z, i))

edges = []
for i in range(3):
    planets.sort(key=lambda x: x[i])
    for j in range(1, n):
        d = abs(planets[j-1][i] - planets[j][i])
        edges.append([d, planets[j-1][3], planets[j][3]])
edges.sort()


def find(x):
    if root[x] != x:
        root[x] = find(root[x])
    return root[x]


def union(x, y):
    root[max(x, y)] = min(x, y)


for w, s, e in edges:
    root_s = find(s)
    root_e = find(e)
    if root_s != root_e:
        union(root_s, root_e)
        answer += w

print(answer)

 

728x90