Search

크루스칼 알고리즘

크루스칼 알고리즘은 대표적인 최소 신장 트리를 찾는 알고리즘이다.

신장트리

그래스에서 모든 노드를 포함하면서 사이클이 존재하지 않는 부분그래프
모든 노드가 포함되어 서로 연결되며 사이클이 존재하지 않는 것은 트리라고도 할 수 있다.
신장트리의 간선 수는 (노드수 -1)개이다. (트리의 기본적 특성)
위 그림의 (a)처럼 사이클이 존재하는 경우는 신장트리라고 할 수 없다.

최소신장트리 문제

최소한의 비용으로 구성되는 신장트리를 찾는 문제이다.
ex) N개의 도시가 존재할 때
두 도시 사이 도로를 놓아 전체 도시가 서로 연결되도록 도로를 설치하는 경우
모든 도시를 최소한의 비용으로 방문하는 경우

크루스칼 알고리즘

최소신장트리 알고리즘
그리디 알고리즘
동작과정
1.
간선 데이터를 비용에 따라 오름차순 정렬 ⇒ 비용이 적은 간선부터 확인
2.
간선 하나씩 확인하면서 현재의 간선이 사이클을 발생시키는지 확인
사이클 발생 x인 경우 : 최소 신장 트리에 포함
사이클 발생 시 : 최소 신장 트리에 포함 x
3.
모든 간선에 대해 2번 반복

예시

간선
(1,2)
(1,5)
(2,3)
(2,6)
(3,4)
(4,6)
(4,7)
(5,6)
(6,7)
비용
29
75
35
34
7
23
13
53
25
(1)오름차순 정렬
간선
(3,4)
(4,7)
(4,6)
(6,7)
(1,2)
(2,6)
(2,3)
(5,6)
(1,5)
비용
7
13
23
25
29
34
35
53
75
(2)
(3, 4) → 두 노드가 같은 집합에 속하여있지 않으므로 union 함수 수행
(4, 7) → union
(4, 6)→ union
(6, 7) → cycle 발생!! pass
(1, 2) → union
(2, 6) → union
(2, 3) → cycle 발생 !! pass
(5, 6) → union
(1, 5) → cycle 발생 !! pass
code
# https://github.com/ndb796/python-for-coding-test/blob/master/10/5.py # 특정 원소가 속한 집합을 찾기 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(v, e, edges): parent = list(range(v+1)) result = 0 # 간선을 비용순으로 정렬 edges.sort() # 간선을 하나씩 확인하며 for edge in edges: cost, a, b = edge # 사이클이 발생하지 않는 경우에만 집합에 포함 if find_parent(parent, a) != find_parent(parent, b): union_parent(parent, a, b) result += cost return result
Python
복사
(2) for edge in edges 반복문 부분을 살펴보기
(3, 4) :
a=3 b=4 cost=7
find_parent(parent, a)→3
find_parent(parent, b)→4
union함수로 parent[4]는 3이 됨
parent : [0, 1, 2, 3, 3, 5, 6, 7]
result = 7
(4, 7)
a=4 b=7 cost=13
find_parent(parent, a) → 3
find_parent(parent, b) → 7
union함수로 parent[7]은 3이 됨
parent: [0, 1, 2, 3, 3, 5, 6, 3]
result = 20
(4, 6)
a=4 b=6 cost=23
find_parent(parent, a) → 3
find_parent(parent, b) → 6
union함수로 parent[6]은 3이 됨
parent: [0, 1, 2, 3, 3, 5, 3, 3]
result = 43
(6, 7)
a=6 b=7 cost=25
find_parent(parent, a) → 3
find_parent(parent, b) → 3
두 노드가 속하는 트리의 루트가 3으로 같으므로 ( 같은 집합에 속하므로) cycle 발생 → pass
(1, 2)
a=1 b=2 cost=29
find_parent(parent, a) → 1
find_parent(parent, b) → 2
union함수로 parent[2]은 1이 됨
parent: [0, 1, 1, 3, 3, 5, 3, 3]
result = 72
(2, 6)
a=2 b=6 cost=34
find_parent(parent, a) → 1
find_parent(parent, b) → 3
union함수로 parent[3]은 1이 됨
parent: [0, 1, 1, 1, 3, 5, 3, 3]
result = 106
(2, 3)
a=2 b=3 cost=35
find_parent(parent, a) → 1
find_parent(parent, b) → 1
두 노드가 속하는 트리의 루트가 1로 같으므로 ( 같은 집합에 속하므로) cycle 발생 → pass
(5, 6)
a=5 b=6 cost=53
find_parent(parent, a) → 5
find_parent(parent, b) → 1
찾는 과정에서 parent[6]이 1이 됨
union함수로 parent[5]은 1이 됨
parent: [0, 1, 1, 1, 3, 1, 1, 3]
result = 159
(1, 5)
a=1 b=5 cost=75
find_parent(parent, a) → 1
find_parent(parent, b) → 1
두 노드가 속하는 트리의 루트가 1로 같으므로 ( 같은 집합에 속하므로) cycle 발생 → pass
⇒ ⇒ result = 159