1. 사이클 판별
서로소 집합 알고리즘은 무방향 그래프에서 사이클을 판별할 때 사용할 수 있다.
방향 그래프에서 사이클 여부는 DFS로 확인할 수 있다고 한다
핵심 원리는 union 연산이 그래프에서의 간선으로 표현될 수 있는데(두 노드를 합치므로)
간선을 하나씩 확인하면서 두 노드가 포함되어 있는 집합을 합치는 과정을 반복하는 것만으로 사이클을 판별할 수 있다.
2. 알고리즘
2-1) 각 간선을 확인하면서 두 노드의 루트 노드를 확인
2-1-1) 루트 노드가 서로 다르다면, 두 노드에 대해 union 연산을 수행
2-1-2) 루트 노드가 서로 같다면 사이클이 발생
2-2) 그래프에 포함된 모든 간선에 대해 위 과정을 반복
3. 예시로 이해하는 사이클 판별 알고리즘
3-1) 초기 단계에서는 모든 노드에 대해 자기 자신을 부모로 설정하는 부모 테이블 생성

3-2) 가장 먼저 간선 1-2를 확인. 노드 1과 노드 2의 루트 노드는 각각 1과 2이다. 루트 노드가 다르다.
그러므로 union 연산을 수행하여 2의 부모 노드를 1로 변경

3-3) 이어서 간선 (1,3)을 확인하고, 각각 루트 노드가 1과 3으로 서로 다르다.
union 연산을 수행하여 3의 부모를 1로 변경한다

3-4) 이후에 간선 (2,3)을 확인한다. 이때 노드 2와 노드 3은 이미 루트 노드로 1을 가지고 있다.
모든 간선을 확인하기 전에 루트 노드가 서로 같은 경우가 발생했으므로 사이클이 발생했다.

4. 구현 예시
사이클 판별 알고리즘은 그래프에 포함되어 있는 간선의 개수가 E개이고
모든 간선을 하나씩 확인하면서 매 간선에 대하여 union및 find함수를 호출하는 방식으로 동작
이는 무방향 그래프에 대해서만 적용 가능하다
#반복구조로 구현한 find 함수
# 원소 x의 대표자를 찾는다
def find_parent(parent,x):
while x != parent[x]:
x = parent[x]
return x
## union 함수
## 두 원소 a,b를 하나로 합친다
def union_parent(parent,a,b):
a = find_parent(parent,a) #a의 대표자를 찾고
b = find_parent(parent,b) #b의 대표자를 찾고
if a < b: #더 큰 번호의 부모를 더 작은 번호로 설정
parent[b] = a
else:
parent[a] = b
#노드의 개수와 간선의 개수
v,e = map(int,input().split())
parent = [0]*(v+1) #부모 번호를 저장할 리스트
##처음엔 자기 자신을 부모로 가지도록 초기화
for i in range(1,v+1):
parent[i] = i
cycle = False ##현재 그래프에서 cycle 발생 여부
#그래프의 모든 간선을 확인
for i in range(e):
a,b = map(int,input().split()) ##간선을 받고
##루트 노드가 서로 동일하다면.. 사이클 발생
if find_parent(parent,a) == find_parent(parent,b):
cycle = True
break
else: ##루트 노드가 다르다면..
union_parent(parent,a,b) ##(a,b)의 union 수행
if cycle:
print('사이클이 발생했습니다.')
else:
print('사이클이 발생하지 않았습니다.')
"""
3 3
1 2
1 3
2 3
사이클이 발생했습니다.
"""'알고리즘 > 분리집합' 카테고리의 다른 글
| union find 재활훈련 - union by size 복기하기 (0) | 2023.01.31 |
|---|---|
| union find 응용문제 풀어보면서 분리집합 개념 재활하기 (0) | 2023.01.09 |
| union find 최적화 - union by size 배우기 (0) | 2022.10.05 |
| union find 알고리즘 최적화 -경로압축과 rank union- (0) | 2022.09.29 |
| union find 알고리즘 (0) | 2022.02.02 |
