-
[백준] 2887번 행성 터널 (by Python)Programming/Algorithm 2021. 3. 13. 23:36
문제
https://www.acmicpc.net/problem/2887
풀이
문제를 보고 사이클을 생성하지 않는 범위 내에서 비용이 적은 순으로 edge를 (v - 1)개까지 선택하는 크루스칼 알고리즘이라는 걸 알 수 있다. 나는 처음에 min(|xA-xB|, |yA-yB|, |zA-zB|) 라고 제시된 각 edge의 비용을 모든 A와 B에 대해 계산하여 시간 초과를 마주하게 되었다. 그리고 좀 더 고민해본 결과 모든 좌표들의 x값, y값, z값을 각각 별도로 정렬한 후 각 축에서 바로 옆에 있는 좌표와의 거리만 edge들만 고려하면 된다는 사실을 알 수 있었다. 간단한 예로, x좌표가 각각 (1, 3, 8)인 점 3개가 주어졌을 때 비용 7을 들여 첫 번째 점과 세 번째 점을 연결하는 것보다 같은 비용으로 첫 번째 점과 두 번째 점을, 두 번째 점과 세 번째 점을 잇는 것이 더 효율적이기 때문이다. 해당 아이디어를 바탕으로 Union-Find 방식을 사용해 크루스칼 알고리즘을 구현했다. 코드는 다음과 같다.
import sys input = sys.stdin.readline def find_parent(x): if parent[x] != x: parent[x] = find_parent(parent[x]) return parent[x] def union_parent(a, b): a = find_parent(a) b = find_parent(b) if a < b: parent[b] = a else: parent[a] = b n = int(input()) parent = list(range(n)) x = [] y = [] z = [] for i in range(n): a, b, c = map(int, input().split()) x.append((a, i)) y.append((b, i)) z.append((c, i)) x.sort() y.sort() z.sort() edges = [] for i in range(n - 1): edges.append((x[i + 1][0] - x[i][0], x[i][1], x[i + 1][1])) edges.append((y[i + 1][0] - y[i][0], y[i][1], y[i + 1][1])) edges.append((z[i + 1][0] - z[i][0], z[i][1], z[i + 1][1])) edges.sort() answer = 0 for e in edges: cost, a, b = e if find_parent(a) != find_parent(b): union_parent(a, b) answer += cost print(answer)
'Programming > Algorithm' 카테고리의 다른 글
[백준] 18310번 안테나 (by Python) (0) 2021.03.14 [백준] 3665번 최종 순위 (by Python) (0) 2021.03.14 [백준] 6064번 카잉 달력 (by Python) (0) 2021.03.07 [백준] 1248번 맞춰봐 (by Python) (0) 2021.03.07 [백준] 1525번 퍼즐 (by Python) (0) 2021.03.05