때는 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보다 작거나 같은 정수이다. 한 위치에 행성이 두 개 이상 있는 경우는 없다.
첫째 줄에 모든 행성을 터널로 연결하는데 필요한 최소 비용을 출력한다.
import sys
input = sys.stdin.readline
def find(x):
if parent[x] != x:
parent[x] = find(parent[x])
return parent[x]
def union(a, b):
a = find(a)
b = find(b)
if a < b:
parent[b] = a
else:
parent[a] = b
N = int(input())
parent = [i for i in range(N+1)]
x = []
y = []
z = []
for i in range(N):
# (x, y, z 좌표, 순서) → 중복 처리 방지
a, b, c = map(int, input().split())
x.append([a, i+1])
y.append([b, i+1])
z.append([c, i+1])
x.sort()
y.sort()
z.sort()
edges = []
for i in range(N-1):
edges.append([abs(x[i+1][0] - x[i][0]), x[i][1], x[i+1][1]])
edges.append([abs(y[i+1][0] - y[i][0]), y[i][1], y[i+1][1]])
edges.append([abs(z[i+1][0] - z[i][0]), z[i][1], z[i+1][1]])
edges.sort()
result = 0
for edge in edges:
cost, a, b = edge
if find(a) != find(b):
union(a, b)
result += cost
print(result)
알고리즘 유형 : 유니온 파인드 + 최소 스패닝 트리
조건을 보면 행성의 개수 N의 최댓값은 100,000으로 2중 for문을 통해 행성 간 최소 거리를 모두 구하기에는 한계가 있다고 판단했다.
min(|xA-xB|, |yA-yB|, |zA-zB|)
일반적인 좌표 간의 거리를 구하는 식이 아닌 각 좌표의 차의 절댓값이 최소 거리가 되게끔 하면 된다.
따라서 x축, y축, z축 기준으로 정렬을 하고 최소 거리를 찾되 이미 연결된 경우를 다시 계산하면 안되기 때문에 인덱스를 추가했다.
이것이 코딩테스트다 with 파이썬 - 행성 터널
모범 답안 - 행성 터널