늘 겸손하게

백준 - 16562번: 친구비 (Python, 분리 집합) 본문

코딩 문제/백준

백준 - 16562번: 친구비 (Python, 분리 집합)

besforyou999 2023. 10. 14. 17:39

 

친구비 

 

문제 유형 : 그래프 이론, 그래프 탐색, 분리 집합

난이도 : 골드 4

 

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

 

 

 

문제 풀이

 

'친구의 친구는 친구' 이기 때문에 분리 집합으로 친구끼리 같은 집합으로 묶은 뒤, 각 집합에서 최소 Ai만 뽑아내어 합했을때 값이 K 이하면 출력, K 초과면 "Oh no"를 출력하면 된다.

 

구현 시 주의사항은, union 메소드로 요소가 다수인 집합과 요소가 다수인 집합을 묶었을때 집합의 모든 root값을 업데이트 해주어야 한다.

 

예로,

 

root[1] = 1

 

root[2] = 2

root[3] = 2

root[4] = 2

 

root[5] = 1

 

이고 union 함수가 

 

def union(a, b):
    a = find_root(a)
    b = find_root(b)
    if a > b:
        root[a] = b
    elif a < b:
        root[b] = a

 

위와 같은 경우 

 

4, 5가 친구라는 입력이 주어지면 

 

root[1] = 1

 

root[2] = 1

root[3] = 2

root[4] = 2

 

root[5] = 1

 

이 되므로 root를 업데이트 해주는 과정이 필요하다.

 

코드

 

import sys
from collections import deque
input = sys.stdin.readline

N, M, k = map(int, input().split())
Ai = deque(map(int, input().split()))
root = [i for i in range(N + 1)]
Ai.appendleft('empty')


def find_root(a):
    if root[a] == a:
        return a
    root[a] = find_root(root[a])
    return root[a]


def union(a, b):
    a = find_root(a)
    b = find_root(b)
    if a > b:
        root[a] = b
    elif a < b:
        root[b] = a

# 친구 사이는 같은 집합으로 묶기
for _ in range(M):
    a, b = map(int, input().split())
    union(a, b)

# 모든 root값 업데이트 과정
for i in range(1, N + 1):
    root[i] = find_root(root[i])

queue = []
# (조상, 친구비)로 배열에 저장
for i in range(1, N + 1):
    r = root[i]
    cost = Ai[i]
    queue.append((r, cost))
    queue.sort(key=lambda x: (x[0], x[1])) # 조상, 친구비 기준으로 오름차순 정렬

prev_root = queue[0][0]
total = queue[0][1]

for i in range(1, N):
    r, cost = queue[i]
    if prev_root == r: # 같은 조상이면 넘어가기
        continue
    else:	# 조상이 다르다면 친구비 합산하고 조상 바꾸기
        prev_root = r
        total += cost

    if total > k: # 친구비가 k 초과하면 Oh no
        print("Oh no")
        sys.exit(0)

print(total)

 

 

마무리