https://www.acmicpc.net/problem/2887
문제
때는 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)
'코딩테스트 > 백준' 카테고리의 다른 글
[백준 5719] 거의 최단 경로 - 다익스트라 알고리즘, bfs 역추적 (0) | 2023.02.05 |
---|---|
[백준 2357] 최솟값과 최댓값 - 세그먼트 트리 (0) | 2023.02.04 |
[백준 1865] 웜홀 - 골드3(벨만-포드 알고리즘) (0) | 2023.02.02 |
[백준 12015] 가장 긴 증가하는 부분 수열 2 - 파이썬(Python) - 골드2(이분 탐색 알고리즘) (0) | 2023.02.01 |
[백준 3665] 최종 순위 - 파이썬(Python) - 골드1(위상 정렬) (0) | 2023.01.31 |