[알고리즘] BOJ 2660 회장뽑기 #Python

김상현·2022년 10월 19일
0

알고리즘

목록 보기
214/301
post-thumbnail

[BOJ] 2660 회장뽑기 바로가기

📍 문제

월드컵 축구의 응원을 위한 모임에서 회장을 선출하려고 한다. 이 모임은 만들어진지 얼마 되지 않았기 때문에 회원 사이에 서로 모르는 사람도 있지만, 몇 사람을 통하면 모두가 서로 알 수 있다. 각 회원은 다른 회원들과 가까운 정도에 따라 점수를 받게 된다.

예를 들어 어느 회원이 다른 모든 회원과 친구이면, 이 회원의 점수는 1점이다. 어느 회원의 점수가 2점이면, 다른 모든 회원이 친구이거나 친구의 친구임을 말한다. 또한 어느 회원의 점수가 3점이면, 다른 모든 회원이 친구이거나, 친구의 친구이거나, 친구의 친구의 친구임을 말한다.

4점, 5점 등은 같은 방법으로 정해진다. 각 회원의 점수를 정할 때 주의할 점은 어떤 두 회원이 친구사이이면서 동시에 친구의 친구사이이면, 이 두사람은 친구사이라고 본다.

회장은 회원들 중에서 점수가 가장 작은 사람이 된다. 회장의 점수와 회장이 될 수 있는 모든 사람을 찾는 프로그램을 작성하시오.


📍 입력

입력의 첫째 줄에는 회원의 수가 있다. 단, 회원의 수는 50명을 넘지 않는다. 둘째 줄 이후로는 한 줄에 두 개의 회원번호가 있는데, 이것은 두 회원이 서로 친구임을 나타낸다. 회원번호는 1부터 회원의 수만큼 붙어 있다. 마지막 줄에는 -1이 두 개 들어있다.


📍 출력

첫째 줄에는 회장 후보의 점수와 후보의 수를 출력하고, 두 번째 줄에는 회장 후보를 오름차순으로 모두 출력한다.


📍 풀이

💡 고찰

  • 양방향 그래프의 한 노드에서 다른 모든 노드에 도달하기 위해 필요한 최소한의 연결선의 개수를 구하는 문제이다.
  • 일반적인 BFS 를 변형하여 문제를 해결하였다.

📌 문제 풀이

✏️ 1. 1 ~ N 까지의 회원의 회장 점수를 저장할 딕셔너리 자료구조를 생성한다.

ranking = defaultdict(list)

✏️ 2. 1 ~ N 까지의 회원의 회장 점수를 탐색한다.

for i in range(1,N+1):
    point = 0
    connection = edges[i]
    visited = [True] + [False] * N
    visited[i] = True
  • pointi 번째 회원의 회장 점수이다.
  • connectioni 번째 회원의 친구 관계이다.
  • visited 는 현재 i 번째 회원과 친구관계인지를 확인하는 자료구조이다.

✏️ 3. 현재 회원의 회장 점수 탐색

while not all(visited): 
    tmp = []
    point += 1
    for node in connection: 
        visited[node] = True
        for nextNode in edges[node]:
            if not visited[nextNode]:
                tmp.append(nextNode)
    connection = tmp
ranking[point].append(i)
  • i 번째 회원이 다른 모든 회원과 친구 관계가 될때까지 반복한다.
  • i 번째 회원의 현재 친구 관계에 해당하는 회원을 모두 친구 관계로 변경한다.
    • 현재 친구 관계의 회원의 친구를 tmp 자료구조애 임시 저장한다.
  • 현재 친구 관계(conncetion)에 대한 탐색이 종료되면 현재 친구 관계를 친구의 친구 관계(tmp) 로 갱신한다.

✍ 코드

from sys import stdin
from collections import defaultdict

def solution(N, edges):
    ranking = defaultdict(list) # { 점수(key) : 회원 번호(value) }

    # 모든 회원 점수 검색
    for i in range(1,N+1):
        point = 0 # 회원 점수
        connection = edges[i] # i번째 회원 친구
        visited = [True] + [False] * N # i번째 회원 친구 관계
        visited[i] = True

        # 모든 회원과 친구 관계가 될때까지 반복
        while not all(visited): 
            tmp = [] # 친구의 친구 관계를 저장할 리스트
            point += 1
            # 현재 회원의 친구 관계에 해당하는 모든 회원 조회
            for node in connection: 
                visited[node] = True # 친구 관계 설정
                # 친구의 친구 관계 tmp에 저장
                for nextNode in edges[node]:
                    if not visited[nextNode]:
                        tmp.append(nextNode)
            # connection을 친구의 친구 관계로 갱신
            connection = tmp
        ranking[point].append(i)
    
    score = min(ranking.keys()) # 회장 후보의 점수
    candidates = sorted(ranking[score]) # 회장 후보

    return score, candidates

# input
edges = defaultdict(list)
N = int(stdin.readline())
while True:
    member1, member2 = map(int,stdin.readline().split())
    if member1 == -1 and member2 == -1:
        break
    edges[member1].append(member2)
    edges[member2].append(member1)

# answer
score, candidates = solution(N, edges)
print(score, len(candidates))
for candidate in candidates: print(candidate,end=' ')
profile
목적 있는 글쓰기

0개의 댓글