알고리즘

[구름] 알고리즘 먼데이 챌린지 0주차 카드 교환하기 파이썬 풀이

최슬슬 2022. 11. 16. 22:17

※사용언어 : 파이썬 

 

▼ 문제 링크 ▼

0주 차 챌린지

 

goorm

구름은 클라우드 기술을 이용하여 누구나 코딩을 배우고, 실력을 평가하고, 소프트웨어를 개발할 수 있는 클라우드 소프트웨어 생태계입니다.

goorm.co

 


 

문제 접근

해당 문제는 구름 측에서 해설지를 제공하고있다.

그럼에도 불구하고 포스팅을 한 이유는 단순히 해설지에 파이썬 코드가 없기 때문이었다.

 

그냥 넘어가긴 조금 아쉬운 감이 있으니 해설지 내용을 간략하게 압축하여 서술하겠다.

해당 문제는 그리디로 접근이 가능하다. 그 이유는 사람의 순번이 작을수록 그 사람이 교환할 수 있는 카드 중 가장 작은 수를 선택해야 하기 때문이다.

예를 들어, 순번이 2, 5, 6 인 사람끼리 카드 교환이 가능하다고 가정하겠습니다. 그리고 세 명의 사람이 가진 카드의 수가  4, 8, 9인 경우 위에 서술한 바와 같이 사람의 순번이 작을수록 카드 숫자가 작은 것을 배치하면 다음과 같습니다. 

사람 2 5 6
카드 4 8 9
불만족지수 2 3 3

총 불만족 지수의 합은 8이 됩니다.

만약 해당 방법이 아닌 다른 방법으로 배치를 하면 어떻게 될까요?

사람 2 5 6
카드 8 4 9
불만족지수 5 1 3

총 불만족 지수는 9가 됩니다. 다르게 카드를 배분해도 절대  불만족 지수는 8 아래로 떨어지지 않습니다.

그렇기 때문에 해당 문제는 카드 교환이 가능한 사람들끼리 그룹으로 묶고(해설지에서는 해당 그룹을 컴포넌트라고 지칭했습니다.) 그룹과, 해당 그룹에 속한 사람들이 가지고 있는 카드를 오름차순으로 정렬해 배분하여 해결할 수 있습니다.

 

 


 

문제풀이(With Python)

import sys
from collections import deque

N, C = map(int, sys.stdin.readline().split(" "))

relation = [[] for _ in range(N+1)]

card_list = list(map(int, sys.stdin.readline().split(" ")))
# 사람의 순번이 1부터 시작하기 때문에 
# 맨 앞에 0을 추가해서 리스트가 1부터 시작하도록 설정
card_list.insert(0,0)

# 관계를 양방향으로 저장
for i in range(C):
    a,b = map(int, sys.stdin.readline().split(" "))
    relation[a].append(b)
    relation[b].append(a)

visited = [False for  _ in range(N+1)]

# 교환이 가능한 사람끼리 그룹화
def bfs(start):
    que = deque()
    component = []
    que.append(start)
    component.append(start)
    visited[start] = True
    while que:
        pos = que.popleft()
        for node in relation[pos]:
            if not visited[node]:
                que.append(node)
                component.append(node)
                visited[node] = True
    return component

# 전체 사람 그룹(컴포넌트)을 저장하는 리스트 생성 
total = []
for i in range(1, N+1):
    if not visited[i]:
        total.append(bfs(i))

dissatisfaction = 0
for people in total:
    cards = []
    # 각 그룹에 속한 사람들이 가지고있는 카드 수 선별
    for p in people:
        cards.append(card_list[p])
    # 그룹 내 사람 정렬
    people.sort()
    # 카드 수 정렬
    cards.sort()
    for person, card in zip(people, cards):
        dissatisfaction += abs(person - card)

print(dissatisfaction)