크루스칼 알고리즘

Ryu·2023년 6월 21일
0

알고리즘

목록 보기
14/14

신장 트리란?

신장 트리는 그래프에서 모든 노드를 포함하면서 사이클이 존재하지 않는 부분 그래프를 의미합니다.
모든 노드가 포함되어 서로 연결되면서 사이클이 존재하지 않는다는 조건은 트리의 조건이기도 합니다.

최소 신장 트리

최소한의 비용으로 구성되는 신장 트리를 찾아야 할 때 어떻게 해야 할까요?

N개의 도시가 존재한다고 가정할 때 두 도시 사이에 도로를 놓아 전체 도시가 연결될 수 있게 도로를 설치한다고 생각할 수 있습니다. 즉, 두 도시 A,B를 선택했을 때 A에서 B로 이동하는 경로가 반드시 존재하도록 도로를 설치합니다.

이때 사용할 수 있는 알고리즘이 바로 크루스칼 알고리즘입니다.

크루스칼 알고리즘

크루스칼 알고리즘은 대표적인 최소 신장 트리 알고리즘이며, 그리디 알고리즘으로 분류됩니다.

동작 과정

  1. 간선 데이터를 비용에 따라 오름차순으로 정렬합니다.
  2. 간선을 하나씩 확인하며 현재의 간선이 사이클을 발생시키는지 확인합니다.
    1) 사이클이 발생하지 않는 경우 최소 신장 트리에 포함시킵니다.
    2) 사이클이 발생하는 경우 최소 신장 트리에 포함시키지 않습니다.
  3. 모든 간선에 대해 2번의 과정을 반복합니다.

동작 예시

[초기 단계] 그래프의 모든 간선 정보에 대하여 오름차순 정렬을 수행합니다.

[Step 1] 아직 처리하지 않은 간선 중에서 가장 짧은 간선인 (3,4)를 선택하여 처리합니다.

[Step 2] 아직 처리하지 않은 간선 중 가장 짧은 간선인 (4,7)을 선택하여 처리합니다.

[Step 3] 아직 처리하지 않은 간선 중 가장 짧은 간선인 (4,6)을 선택하여 처리합니다.

[Step 4] 아직 처리하지 않은 간선 중 가장 짧은 간선인 (6,7)을 선택하여 처리합니다.
6번 노드와 7번 노드는 이미 같은 집합에 속해있으므로 간선을 포함한다면 사이클이 생깁니다. 따라서 해당 간선은 무시하고 넘어갑니다.

[Step 5] 아직 처리하지 않은 간선 중 가장 짧은 간선인 (1,2)을 선택하여 처리합니다.

이 과정을 반복하면 다음과 같은 결과를 얻게 됩니다.


결과로 얻은 최소 신장 트리에 포함되어있는 간선의 비용을 모두 더하면, 그 값이 최종 비용에 해당합니다.

구현

import sys
input = sys.stdin.readline

v,e = map(int,input().split())
parent = [i for i in range(v+1)]
graph=[]
result = 0

for _ in range(e):
  a,b,c = map(int,input().split())
  graph.append((c,a,b))

# 비용 순으로 정렬
graph.sort()

# 특정 원소가 속한 집합을 찾을 때까지 
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

for i in graph:
  cost,a,b = i
  # 사이클이 발생하지 않는 경우에만 집합에 포함
  if find_parent(parent,a)!=find_parent(parent,b):
    union_parent(parent,a,b)
    result += cost

print(result)

성능 분석

크루스칼 알고리즘은 간선의 개수가 E개일 때, O(ElogE)의 시간 복잡도를 가집니다.
크루스칼 알고리즘에서 가장 많은 시간을 요구하는 곳은 간선을 정렬하는 부분입니다.

profile
나는야 머찐 개발자

0개의 댓글