n개의 섬 사이에 다리를 건설하는 비용(costs)이 주어질 때, 최소의 비용으로 모든 섬이 서로 통행 가능하도록 만들 때 필요한 최소 비용을 return 하도록 solution을 완성하세요.
다리를 여러 번 건너더라도, 도달할 수만 있으면 통행 가능하다고 봅니다. 예를 들어 A 섬과 B 섬 사이에 다리가 있고, B 섬과 C 섬 사이에 다리가 있으면 A 섬과 C 섬은 서로 통행 가능합니다.
n | costs | return |
---|---|---|
4 | [[0,1,1],[0,2,2],[1,2,5],[1,3,1],[2,3,8]] | 4 |
costs를 그림으로 표현하면 다음과 같으며, 이때 초록색 경로로 연결하는 것이 가장 적은 비용으로 모두를 통행할 수 있도록 만드는 방법입니다.
'최소 신장 트리'를 찾아내는 문제로서, 그리디의 일종인 '크루스칼 알고리즘(Kruskal algorithm)'을 사용해 해결하는 문제이다. 크루스칼 알고리즘 포스트에 전반적인 내용이 있으니 여기서는 간단하게만 정리한다.
def solution(n, costs):
# 간선 정보를 비용을 기준으로 정렬
costs.sort(key=lambda x: x[2])
# 부모 노드 테이블 생성 후 초기화
parent = [0] * (n)
for i in range(n):
parent[i] = i
# find 함수와 union 함수 선언
def find(parent, x):
# 자기 자신이 루트 노드가 아닐 경우 루트 노드를 찾을 때까지 재귀적으로 호출
if parent[x] != x:
# return find(parent, parent[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
# 간선 정보를 순회하면서 크루스칼 알고리즘 수행
def kruskal(costs, parent):
tree_cost = 0
for a, b, cost in costs:
# 두 노드 간의 사이클 여부 확인
if find(parent, a) != find(parent, b):
union(parent, a, b)
tree_cost += cost
return tree_cost
answer = kruskal(costs, parent)
return answer