Union & Find 알고리즘

    Union & Find

    union & Find 이라는 알고리즘은 Union과 Find으로 이루어져있다.

    Union은 합치기

    Find는 찾기

     

    두 집합이 같은 집합에 있는지 확인하기위해 트리를 사용해서 하나의 집합에 있는지 확인하는 방법이다.

     

    예를들어 A라는 집합에 1 3 5 7 9가있고 B라는 집합엔 2 4 6 8이 있다.

    그리고 1 2 3 4 5 6 7 8 9중에 랜덤한 두 수가 같은 집합인지 물어본다고 한다.

    1 5는 같은 집합인가요? 네

    2 6은 같은 집합인가요? 네

    1 8은 같은 집합인가요? 아니오

     

    이런 방법을 판별하기 위해 for문으로 1~9까지 반복한다면 O(N)이 나온다.

    하지만 Union & Find로 판별한다면 트리의 높이만큼 탐색할 때와 같이 O(logN)이 나온다.

     

    Union & Find는 구현하기위해 각 집합을 트리로 구현하며 최상위 부모가 최솟값이 되어야 한다.

    즉, 올라갈수록 더 작은값이 되어야 한다.

    물론 최대값으로 만들어도 상관없지만 일방적으로 최솟값이 되도록 구현한다.

     

     

     

     

     

    사용법

    Union & Find에서 중요한 것은 Find이다.

     

    Find는 현재 트리에서 최상위 부모(최솟값)을 찾는 과정이다.

    파이썬의 구현 코드

    def find(x):
        if parent[x] != x:
            return find(parent[x])
        return x

    재귀함수를 활용해서 부모를 찾으면 된다.

     

    Union은 두 개의 트리를 합하는 방법이다.

    파이썬의 구현 코드

    def union(a,b):
        x = find(a)
        y = find(b)
        if x < y: parent[y] = x
        else: parent[x] = y

    a라는 트리와 b라는 트리의 부모를 찾는다.

    두 트리중 부모의 값이 더 작은 값쪽으로 트리를 붙인다.

     

     

     

     

    1~9까지 수를 짝수와 홀수로 나눠서 무작위로 입력한다고 가정하자.

     

    위 그림에서 짝수와 홀수로 구분지어서 합하기 위해 순서대로 입력이 들어오면 합친다고 한다.

     

    1 3

     

    9 7

     

    7 3

     

    1 5

    이렇게 홀수가 만들어졌다고 하자.

    그리고 짝수는 

    8 6

    6 4

    4 2

    의 순서로 입력이 들어와서 이렇게 구현되었다고 하자.

    이러면 확실하게 부모노드가 1과 2로 구분되어져서 두 집합이 구분되어 있는게 보인다.

     

     

    하지만 이렇게만 구현한다면 경로 압축이 되지않아서 최악의 경우 O(2N)의 탐색을 해야할 수도 있다.

    9 8

    8 7

    7 6

    ...

    3 2

    2 1

    으로 입력이 주어진 경우다.

    부모를 탐색하기위해 9의 부모를 찾으려면 1까지 올라갔다가 내려와야한다.

    이를 위해 경로탐색을 해줘야 한다.

     

     

    경로 압축

    어려워 보이지만 별로 어려울게 없다.

    Find에서 한줄만 더 적으면 된다.

    def find(x):
        if parent[x] != x:
            parent[x] = find(parent[x])
            return parent[x]
        return x

     

     

     

     

     

    Find에서 부모노드를 찾으면서 최상위 부모에 등록을 해버리는 방법이다.

    이러면 경로가 압축되기 때문에 탐색 시간을 단축시킬 수 있다.

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    추가 문제

    https://www.acmicpc.net/problem/1717

     

    1717번: 집합의 표현

    첫째 줄에 n(1 ≤ n ≤ 1,000,000), m(1 ≤ m ≤ 100,000)이 주어진다. m은 입력으로 주어지는 연산의 개수이다. 다음 m개의 줄에는 각각의 연산이 주어진다. 합집합은 0 a b의 형태로 입력이 주어진다. 이는

    www.acmicpc.net

     

     

     

     

     

     

     

     

     

     

     

     

     

    참고 링크

    https://gmlwjd9405.github.io/2018/08/31/algorithm-union-find.html

     

    [알고리즘] Union-Find 알고리즘 - Heee's Development Blog

    Step by step goes a long way.

    gmlwjd9405.github.io

    https://www.youtube.com/watch?v=AMByrd53PHM&t=378s 

     

     

    '백준 > 이론_python' 카테고리의 다른 글

    문자열 뒤집기 python  (0) 2023.04.11
    나머지 분배법칙(모듈러 연산)  (0) 2023.02.11
    백준의 long과 int의 차이  (0) 2023.02.11
    비트 마스킹 C++  (0) 2023.01.17
    분할 정복 알고리즘 python  (0) 2023.01.16

    댓글