ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Union-Find 알고리즘
    Algorithms in Python/notes 2021. 2. 7. 08:30

     

    Union-Find (서로소 집합) 자료구조

    서로소 부분 집합들로 나누어진 원소들의 데이터를 처리하기 위한 자료구조

     

    union(합집합) 연산 : 2개의 원소가 포함된 집합을 하나의 집합으로 합치는 연산

    find(찾기) 연산 : 특정한 원소가 속한 집합이 어떤 집합인지 알려주는 연산

     

    Union-Find 알고리즘

    1. union(합집합) 연산을 확인하여, 서로 연결된 두 노드 A, B를 확인한다.

        - A와 B의 루트 노드 A', B'를 각각 찾는다.

        - A'를 B'의 부모 노드로 설정한다. (B'가 A'를 가리키도록 한다.)

    2. 모든 union(합집합) 연산을 처리할 때까지 1번 과정을 반복한다.

     

    * 일반적으로 더 번호가 작은 원소가 부모 노드(작은 원소를 가르킴)가 되도록 구현하는 경우가 많다.

    * 부모 테이블을 통해 수행한다.

     

    Union-Find 알고리즘 소스코드

    # 특정 원소가 속한 집합을 찾기
    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
    
    # 노드의 개수와 간선(union 연산)의 개수 입력받기
    v, e = map(int, input().split())
    parent = [0] * (v + 1)  # 부모테이블 초기화
    
    # 부모 테이블상에서, 부모를 자기 자신으로 초기화
    for i in range(1, v + 1):
        parent[i] = i
    
    # union 연산을 각각 수행
    for i in range(e):
        a, b = map(int, input().split())
        union_parent(parent, a, b)
    
    # 각 원소가 속한 집합 출력
    print("각 원소가 속한 집합: ", end=' ')
    for i in range(1, v + 1):
        print(find_parent(parent, i), end=' ')
    
    print()
    
    # 부모 테이블 내용 출력
    print("부모 테이블: ", end=' ')
    for i in range(1, v + 1):
        print(parent[i], end=' ')

     

    Union-Find 알고리즘의 시간 복잡도

    노드의 개수 V, 최대 V - 1개의 union 연산과 M개의 find 연산이 가능할 때

    O(V + M(1 + log2-M/VV)

     

    Union-Find를 활용한 사이클 판별

    서로소 집합은 그래프 내에서의 사이클을 판별할 때 사용할 수 있다.

    union연산은 그래프에서의 간선으로 표현될 수 있다. 따라서 간선을 하나씩 확인하면서 두 노드가 포함되어있는 집합을 합치는 과정을 반복하면 사이클을 판별할 수 있다.

     

    1. 각 간선을 확인하며 두 노드의 루트 노드를 확인한다.

        - 루트 노드가 서로 다르다면 두 노드에 대하여 union 연산을 수행한다.

        - 루트 노드가 서로 같다면 사이클이 발생한 것이다.

    2. 그래프에 포함되어 있는 모든 간선에 대하여 1번 과정을 반복한다.

     

     서로소 집합을 활용한 사이클 판별 소스코드

    cycle = False # 사이클 발생 여부
    
    for i in range(e):
        a, b = map(int, input().split())
        # 사이클이 발생한 경우 종류
        if find_parent(parent, a) == find_parent(parent, b):
            cycle = True
            break
        # 사이클이 발생하지 않았다면 합집합(union) 수행
        else:
            union_parent(parent, a, b)
    
    if cycle:
        print("사이클이 발생했습니다.")
    else:
        print("사이클이 발생하지 않았습니다.")

     

     

    * 이것이 코딩테스트다 with 파이썬 - 나동빈

    'Algorithms in Python > notes' 카테고리의 다른 글

    위상 정렬  (0) 2021.02.07
    크루스칼 알고리즘  (0) 2021.02.07
    DFS / BFS  (0) 2021.01.29
    이진 탐색, bisect 라이브러리  (0) 2021.01.21
    파이썬의 정렬 라이브러리  (0) 2021.01.20

    댓글

Designed by Tistory.