Updated:

πŸ™…Β Disjoint Set

μ„œλ‘œ κ³΅ν†΅λœ μ›μ†Œλ₯Ό 가지고 μžˆμ§€ μ•Šμ€ μ—¬λŸ¬ 집합듀을 μ§€μΉ­ν•˜λŠ” μš©μ–΄λ‹€. κ°œλ³„ μ›μ†Œκ°€ μ •ν™•νžˆ ν•˜λ‚˜μ˜ 집합에 μ†ν•˜λ©°, μ–΄λ–€ 집합도 μ„œλ‘œ 곡톡 μ›μ†Œλ₯Ό 가지고 μžˆμ§€ μ•Šμ•„μ•Ό ν•œλ‹€. μ„œλ‘œμ†Œ 집합 자료ꡬ쑰λ₯Ό μ‚¬μš©ν•˜λ©΄ μ„œλ‘œ λ‹€λ₯Έ μ›μ†Œλ“€μ΄ 같은 집합ꡰ에 속해 μžˆλŠ”κ°€ νŒλ³„ν•˜λŠ” 것과 같은 μž‘μ—…μ„ μ‰½κ²Œ ν•  수 μžˆλ‹€. κ·Έλ ‡λ‹€λ©΄ μ΄μ œλΆ€ν„° μžλ£Œκ΅¬μ‘°λ‘œμ„œ μ„œλ‘œμ†Œ 집합을 효과적으둜 ν‘œν˜„ν•˜κ³  μ‘°μž‘ν•  수 μžˆλŠ” Makeset, Union, Find 연산에 λŒ€ν•΄μ„œ μ•Œμ•„λ³΄μž.

πŸ—‚οΈΒ Makeset

트리 자료ꡬ쑰λ₯Ό ν™œμš©ν•΄ 집합을 ν‘œν˜„ν•˜λŠ” 방법 쀑 ν•˜λ‚˜λ‘œ, 주어진 μš”μ†Œλ§Œ 쀑볡없이 ν¬ν•¨ν•˜λŠ” 집합을 μƒμ„±ν•˜λŠ” 연산이닀. μ‹€μ œ μ½”λ“œμƒ κ΅¬ν˜„μœΌλ‘œλŠ” λ°°μ—΄, 리슀트 자료ꡬ쑰λ₯Ό ν™œμš©ν•œλ‹€. λ°°μ—΄μ˜ 인덱슀λ₯Ό κ°œλ³„ μ›μ†Œμ˜ μ‹λ³„μžλ‘œ κ°„μ£Όν•˜κ³  ν•΄λ‹Ή μœ„μΉ˜μ˜ κ°’μ—λŠ” λΆ€λͺ¨ μ›μ†Œμ˜ 인덱슀λ₯Ό μ±„μ›Œ λ„£λŠ”λ‹€. λ§Œμ•½ μΈλ±μŠ€μ™€ μ›μ†Œκ°’μ΄ λ™μΌν•˜λ‹€λ©΄ ν•΄λ‹Ή μ›μ†Œκ°€ ν¬ν•¨λœ μ§‘ν•©μ—μ„œ ν˜„μž¬ μ›μ†Œκ°€ 루트 λ…Έλ“œμž„μ„ μ˜λ―Έν•œλ‹€. μ΄λ ‡κ²Œ νŠΉμ • 인덱슀의 μ›μ†Œκ°’μ„ 타고 거슬러 μ˜¬λΌκ°€λ‹€λ©΄ λ§Œλ‚˜κ²Œ λ˜λŠ” 루트 λ…Έλ“œμ˜ 값을 μ΄μš©ν•΄ μš°λ¦¬λŠ” μ„œλ‘œ λ‹€λ₯Έ 두 μ›μ†Œκ°€ 같은 집합에 μ†ν•˜λŠ”μ§€ ν˜Ήμ€ λ‹€λ₯Έ 집합에 μ†ν•˜λŠ”μ§€ ꡬ별할 수 있게 λœλ‹€.

""" Disjoint Makeset Example """

N = int(sys.stdin.readline()) # λ…Έλ“œ 개수
M = int(sys.stdin.readline()) # 엣지 개수
parent = [0]*(N+1)

# 1) Makeset Array Init
for i in range(1, N+1):
    parent[i] = i

λ°°μ—΄μ˜ 인덱슀λ₯Ό κ°œλ³„ λ…Έλ“œμ˜ μ‹λ³„μžλ‘œ μ‚¬μš©ν•˜κΈ° μœ„ν•΄, 전체 κ·Έλž˜ν”„ μƒμ˜ λ…Έλ“œ 개수만큼 λ°°μ—΄μ˜ 크기λ₯Ό μ΄ˆκΈ°ν™” ν•΄μ£Όκ³  μžˆλ‹€. 그리고 μ΄ˆκΈ°μ—λŠ” 아직 λ…Έλ“œ μ‚¬μ΄μ˜ μ—°κ²° 정보에 λŒ€ν•΄μ„œ μ£Όμ–΄μ§„κ²Œ μ „ν˜€ μ—†κΈ° λ•Œλ¬Έμ— κ°œλ³„ λ…Έλ“œ μžμ‹ μ΄ 루트 λ…Έλ“œκ°€ λ˜λ„λ‘ μ΄ˆκΈ°ν™”λ₯Ό ν•΄μ£ΌλŠ”κ²Œ μΌλ°˜μ μ΄λ‹€. μ΄λ ‡κ²Œ μ΄ˆκΈ°ν™”ν•œ 배열은 Union, Find 연산에 ν™œμš©λœλ‹€.

πŸ”¬Β Find

μ–΄λ–€ μ›μ†Œκ°€ μ†ν•œ μ§‘ν•©μ˜ 루트 λ…Έλ“œ 값을 λ°˜ν™˜ν•˜λŠ” 연산이닀. Find 연산은 μ•žμ„œ μ΄ˆκΈ°ν™”ν•œ Makeset Array λ₯Ό ν•΄λ‹Ή 집합(트리)의 루트 λ…Έλ“œλ₯Ό λ§Œλ‚  λ•ŒκΉŒμ§€ μž¬κ·€μ μœΌλ‘œ μˆœνšŒν•œλ‹€. μ‹€μ œλ‘œλŠ” λ‹¨μˆœ 루트 λ…Έλ“œλ₯Ό λ°˜ν™˜ν•˜λŠ” μš©λ„λ‘œ μ‚¬μš©ν•˜μ§€ μ•Šκ³ , νŠΉμ • 두 μ›μ†Œκ°€ 같은 집합(트리)에 μ†ν•˜λŠ”μ§€ μ•„λ‹ˆλ©΄ μ„œλ‘œ λ‹€λ₯Έ 집합에 μ†ν•˜λŠ”μ§€ νŒμ •ν•˜λŠ”λ° μ‚¬μš©λœλ‹€. μ„œλ‘œ λ‹€λ₯Έ 두 μ›μ†Œλ₯Ό Find μ—°μ‚°μžμ— λ„£μ–΄μ£Όλ©΄ 각각의 루트 λ…Έλ“œλ₯Ό ꡬ할 수 μžˆλŠ”λ°, 이 λ•Œ μ„œλ‘œ 같은 루트 λ…Έλ“œκ°’μ„ λ°˜ν™˜ν•œλ‹€λ©΄ 같은 집합이라고 κ°„μ£Όν•˜κ³  λ‹€λ₯΄λ‹€λ©΄ μ„œλ‘œ μ„œλ‘œμ†Œ 관계에 μžˆλ‹€κ³  νŒλ‹¨ν•  수 μžˆλ‹€.

""" find method """

def find(arr: list, x: int) -> int:
    """ method for finding root node """
    if arr[x] != x:
        arr[x] = find(arr, arr[x])
    return arr[x]

# 1) Kruskal Algorithm
result = 0
for j in range(M):
    weight, start, final = graph[j]
    if find(parent, start) != find(parent, final):
        union(parent, start, final)
        result += weight

μœ„ μ†ŒμŠ€μ½”λ“œμ²˜λŸΌ Kruskal Algorithm처럼 μ΅œμ†Œ μŠ€νŒ¨λ‹ νŠΈλ¦¬κ°€ ν•„μš”ν•œ 상황에 자주 μ‚¬μš©λœλ‹€. λ˜ν•œ 근본이 트리 μžλ£Œκ΅¬μ‘°μ— λŒ€ν•œ μ—°μ‚°μ΄λΌλŠ” 점을 ν™œμš©ν•΄, νŠΉμ • κ·Έλž˜ν”„μ˜ 사이클 μ—¬λΆ€λ₯Ό νŒμ •ν•˜λŠ” μ•Œκ³ λ¦¬μ¦˜μœΌλ‘œλ„ 많이 μ‚¬μš©λ˜κ³  μžˆλ‹€.

πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘¦Β Union

두 개의 집합을 ν•˜λ‚˜λ‘œ ν•©μΉ˜λŠ” 연산이닀. μ§‘ν•©μ˜ 루트 λ…Έλ“œλ₯Ό λ‹€λ₯Έ μ§‘ν•©μ˜ 루트 λ…Έλ“œ μ•„λž˜μ— μ—°κ²°ν•˜λŠ” λ°©μ‹μœΌλ‘œ ν•©μΉœλ‹€. ν•©μΉ˜λŠ” λ°©μ‹μ—λŠ” λ‹€μ–‘ν•œ 방법둠이 μ‘΄μž¬ν•˜λŠ”λ°, 일반적으둜 루트 λ…Έλ“œμ˜ λ²ˆν˜Έκ°€ 더 μž‘μ€ μͺ½μ— 더 큰 μͺ½μ˜ 집합(트리)λ₯Ό λΆ™μ—¬μ£ΌλŠ” Union by Rank 방식을 많이 μ‚¬μš©ν•œλ‹€.

""" union method """

def union(arr: list, x: int, y: int):
    """ method for union-find """
    x = find(arr, x)
    y = find(arr, y)
    if x < y:
        arr[y] = x
    else:
        arr[x] = y

# 1) Kruskal Algorithm
result = 0
for j in range(M):
    weight, start, final = graph[j]
    if find(parent, start) != find(parent, final):
        union(parent, start, final)
        result += weight

print(result)

μ—­μ‹œ λ§ˆμ°¬κ°€μ§€λ‘œ μ΅œμ†Œ μŠ€νŒ¨λ‹ νŠΈλ¦¬κ°€ ν•„μš”ν•œ 상황에 자주 μ‚¬μš©λ˜κ³  있으며, 주둜 Findλ₯Ό 톡해 μ„œλ‘œμ†Œ 집합 관계에 놓인 집합듀을 νŒμ •ν•˜κ³ , 그듀을 ν•˜λ‚˜λ‘œ ν†΅ν•©μ‹œν‚€λŠ”λ° 자주 쓰인닀.

Leave a comment