그래프 연결요소 - union find로 찾아야하는 연결요소 문제 1 -
1. 문제
D - Unicyclic Components (atcoder.jp)
D - Unicyclic Components
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.
atcoder.jp
주어진 그래프에서 모든 연결요소가 정점의 개수와 간선의 개수가 같은지 판단하는 문제
2. 풀이
연결요소 하니까 BFS로 찾아볼려고 했는데.. 이게 간선을 관리하기가 만만치 않다
심지어 이 문제는 두 정점 사이 간선이 여러개 있어도 상관없고, 동일한 정점에 간선이 있는 루프도 있다
editorial 피셜로 "One can manage the connectivity of an undirected graph easily with a data structure called Union-Find"
방향이 없는 그래프의 연결성을 관리하는 한가지 쉬운 자료구조는 union find
---------------------------------------------------------------------------------------------------------------------------------------------
rank를 "집합에 포함된 간선의 수"로 정의한다.
union만 실수하지 않으면 문제가 없는데
1) union 할때마다 간선이 1개 추가되는 거니까 해당 집합에 1이 더해져야 할거고
2) 루프가 들어갈 수 있기 때문에 a,b가 서로 같을 수 있다.
이런 경우에 parent를 조절해버리면, parent[a] = a가 되어버려서 초기화 상태로 돌아가 문제가 생긴다
그러니까 a,b가 서로 같다면, 간선에 1을 더해 rank만 조절하고 return시킨다
3) union시 단순히 rank에 1만 더해지는게 아니고 두 집합 a,b가 union되면, 두 집합 a,b가 가지고 있는 간선이 모두 합쳐져야겠지
def union(a,b,parent):
a = find_parent(a,parent)
b = find_parent(b,parent)
if a == b:
rank[a] += 1
rank[b] = rank[a]
return
if rank[a] > rank[b]:
parent[b] = a
else:
parent[a] = b
rank[a] += rank[b]
rank[a] += 1
rank[b] = rank[a]
parent, rank를 초기화한 다음에
이제 간선을 받을때마다 union을 시키고
1번부터 n번까지 순회하여 각 정점의 대표자를 찾는다
대표자를 찾을때는 parent값을 찾는게 아니라, find_parent에 넣어야한다는건 이제 기본
그리고 해당 대표자가 하나의 연결요소 component를 이룰 것이다.
그래서 그 component에 append시켜준다
n,m = map(int,input().split())
parent = [i for i in range(n+1)]
rank = [0]*(n+1)
for _ in range(m):
u,v = map(int,input().split())
union(u,v,parent)
component = [[] for _ in range(n+1)]
for i in range(1,n+1):
s = find_parent(i,parent)
component[s].append(i)
다시 1번부터 n번까지 순회하여, component가 비어있지 않다면,
해당 집합의 rank는 해당 component의 간선의 수이고, 이것과 component에 들어간 정점의 수가 모두 일치해야한다
def find_parent(x,parent):
if x != parent[x]:
parent[x] = find_parent(parent[x],parent)
return parent[x]
def union(a,b,parent):
a = find_parent(a,parent)
b = find_parent(b,parent)
if a == b:
rank[a] += 1
rank[b] = rank[a]
return
if rank[a] > rank[b]:
parent[b] = a
else:
parent[a] = b
rank[a] += rank[b]
rank[a] += 1
rank[b] = rank[a]
n,m = map(int,input().split())
parent = [i for i in range(n+1)]
rank = [0]*(n+1)
for _ in range(m):
u,v = map(int,input().split())
union(u,v,parent)
component = [[] for _ in range(n+1)]
for i in range(1,n+1):
s = find_parent(i,parent)
component[s].append(i)
yes = True
for i in range(1,n+1):
a = len(component[i])
if a != 0:
if rank[i] != len(component[i]):
yes = False
break
if yes:
print("Yes")
else:
print("No")
'경쟁 프로그래밍 > Atcoder' 카테고리의 다른 글
ABC 304 복기 - E good graph - union find 활용 (0) | 2023.06.04 |
---|---|
ABC 301 복기.. C - AtCoder Cards (문자열 그리디 알고리즘) (0) | 2023.05.14 |
ABC 293 복기 E - Geometric Progression - 행렬곱 배우기 - (0) | 2023.03.12 |
ABC 293 복기 - D Tying Rope - 그래프 연결요소, cycle 판단 - (0) | 2023.03.12 |
정수론 - 방정식을 만족하는 순서쌍의 수 세기 - 브루트포스 탐색 범위 줄이는 테크닉 익히기 (0) | 2023.03.11 |