TIL (2022.02.09)
➕ 오늘 푼 문제
프로그래머스 - 섬 연결하기
➕ 아이디어
크루스칼 알고리즘
- 가장 적은 비용으로 모든 노드를 연결하기 위해 사용하는 알고리즘
- 최소 비용 신장 트리를 만들기 위한 대표적인 알고리즘
- 최소 비용 신장 트리에서는 사이클이 발생하면 안됩니다. 애초에 모든 노드를 이어 붙이기만 하면 되는데 사이클이 발생할 이유가 없습니다.
- 구현 방법
- 정렬된 순서에 맞게 그래프에 포함시킵니다.
- 포함시키기 전에는 사이클 테이블을 확인합니다.
- 사이클을 형성하는 경우 간선을 포함하지 않습니다.
- 사이클 형성 여부는 Union-find 알고리즘으로 확인할 수 있습니다.
- 시간 복잡도
- 크루스칼 알고리즘 = 정렬 알고리즘 + Union-Find 알고리즘
- 사실상 정렬 알고리즘의 시간 복잡도를 따른다고 봐도 무방하다.
문제 해결 방법
- 크루스칼 알고리즘을 이용하여, 최소 비용을 구한다
- 간선을 비용 기준으로 정렬한다.
- 모든 간선을 탐색하면서 사이클이 발생하는지 확인한다 (
find_parent
)
- 사이클이 발생하지 않는다면, 부모를 합치고(
union_parent
) 비용을 추가한다.
➕ Java 코드
import java.util.*;
class Solution {
public int findParent(int[] parent, int x){
if(parent[x] != x){
parent[x] = findParent(parent, parent[x]);
}
return parent[x];
}
public void unionParent(int[] parent, int a, int b){
a = findParent(parent, a);
b = findParent(parent, b);
if(a < b){
parent[b] = a;
}else{
parent[a] = b;
}
}
public int solution(int n, int[][] costs) {
int answer = 0;
int[] parent = new int[n];
for(int i=0; i<n; i++){
parent[i] = i;
}
Arrays.sort(costs, (o1, o2) -> Integer.compare(o1[2], o2[2]));
for(int i=0; i<costs.length; i++){
int a = costs[i][0];
int b = costs[i][1];
int c = costs[i][2];
if(findParent(parent, a) != findParent(parent, b)){
unionParent(parent, a, b);
answer += c;
}
}
return answer;
}
}
➕ Python 코드
def find_parent(parent, x):
if parent[x] != x:
parent[x] = find_parent(parent, parent[x])
return parent[x]
def union_parent(parent, a, b):
a = find_parent(parent, a)
b = find_parent(parent, b)
if a < b:
parent[b] = a
else:
parent[a] = b
def solution(n, costs):
answer = 0
parent = [i for i in range(n)]
costs.sort(key=lambda x:x[2])
for a, b, c in costs:
if find_parent(parent, a) != find_parent(parent, b):
union_parent(parent, a, b)
answer += c
return answer
➕ 궁금한 내용 및 소감
- 크루스칼 알고리즘에 대해서 알고는 있었는데, 적용 안 해본 지 너무 오래라 이 문제에서 사용할 생각을 못했다. 다행히 알고리즘 자체는 얼추 기억하고 있어서, 이해하고 푸니 그렇게 어렵게 느껴지지는 않았다. 잊고 있던 알고리즘을 복습할 수 있는 기회였다~!
➕ 참고 문헌