코딩 테스트 연습/백준 silver

[백준] S2. 랭킹전 대기열 (Python)

카누가 좋아요 2023. 6. 19. 13:05

❓ 문제

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

 

20006번: 랭킹전 대기열

모든 생성된 방에 대해서 게임의 시작 유무와 방에 들어있는 플레이어들의 레벨과 아이디를 출력한다. 시작 유무와 플레이어의 정보들은 줄 바꿈으로 구분되며 레벨과 아이디는 한 줄에서 공백

www.acmicpc.net

 

 

 

💡 해결하기

이 문제는 플레이어의 레벨과 닉네임에 관한 정보를 한 줄씩 입력받을 때마다 알맞은 방에 넣어 주고, 모든 플레이어들이 방에 들어갔을 때 각 방에 정원이 다 찼는지 여부에 따라 출력값이 달라지는 형태로 코드를 짜야 한다.

이때 각 방room 리스트로 표현하고, 각 플레이어들은 room 리스트의 원소가 되도록 설계하였다. rooms 리스트는 각 방들인 room 리스트들을 원소로 하는 하나의 리스트로 만들었다. 이렇게 이차원 리스트의 구조를 이용하였다.

 

문제에서 주어진 플레이어 간 매칭 시스템에 대해 살펴보자.

 

1️⃣ 플레이어가 입장을 신청하였을 때 매칭이 가능한 방이 없다면 새로운 방을 생성하고 입장시킨다. 이때 해당 방에는 처음 입장한 플레이어의 레벨을 기준으로 -10부터 +10까지 입장 가능하다.

➡️ 매칭이 가능한 방이 없는 경우가장 처음으로 입력된 플레이어이거나 위에 적힌 대로 레벨이 +-10 조건을 충족하지 못하는 플레이어일 경우이다.

➡️ 위와 같은 경우에는 새로운 방을 생성해야 하므로 새로운 room 리스트를 만들어 해당 플레이어를 넣어주고, 그 플레이어는 새로운 room에 처음 입장한 플레이어가 된다. 이 room 리스트를 rooms 리스트에 새로 추가해 주면 된다.

 

2️⃣ 입장 가능한 방이 있다면 입장시킨 후 방의 정원이 모두 찰 때까지 대기시킨다. 이때 입장이 가능한 방이 여러 개라면 먼저 생성된 방에 입장한다.

➡️ 방의 정원이 모두 찬 room 리스트에는 더 이상 플레이어를 추가하는 것이 불가하다는 의미이다.

➡️ rooms 리스트의 원소인 room 리스트를 0번부터 하나씩 탐색하여 해당 room에 정원이 다 차지 않은 상태이면서 현재 플레이어가 1번에서 말하는 +-10 조건을 만족시킨다면 그 플레이어는 해당 room에 들어갈 수 있게 된다. 

 

3️⃣ 방의 정원이 모두 차면 게임을 시작시킨다.

➡️ rooms 리스트의 원소인 room 리스트들을 하나씩 탐색하면서 방의 정원과 해당 room 리스트 안에 있는 사람의 수가 일치한다면 Started! 를 출력하고 사람의 수가 정원 수 보다 작다면 Waiting! 을 출력해야 한다.

➡️ 둘 중의 한 문구를 출력 후 바로 다음에는 그 room 안에 있는 플레이어들의 레벨과 닉네임을 출력해야 한다. 이때, 닉네임이 오름차순인 순서대로 출력해야 한다는 출력 조건을 잊지 말아야 한다.

 

예제 입력 1에 나온 경우를 위의 논리대로 도식화해보면 다음과 같다. 

 

 

 

💻 Python으로 코드 작성하기

 

p, m = map(int, input().split())     # 플레이어의 수, 방의 정원
rooms = []     # 여러 개의 방들이 들어갈 리스트

# 방 구성하기
for _ in range(p):
    lv, name = input().split()
    if len(rooms) == 0:     # rooms 리스트에 방이 하나도 없는 경우
        rooms.append([[int(lv), name]])      # 새 방을 만듦과 동시에 현재 player 정보 넣기
    else:     # 이미 방이 존재하는 경우
        for room in rooms:      # 방을 0번부터 하나씩 탐색
            first_lv = room[0][0]     # 각 방에 처음 입장한 player의 레벨
            if len(room) < m and first_lv - 10 <= int(lv) <= first_lv + 10:     # 방의 정원이 꽉 차있지 않으면서 현재 player의 레벨이 first_lv의 +-10 범위에 있다면
                room.append([lv, name])     # 그 방에 현재 player 입장
                break     # 입장이 완료되면 반복문 종료
        else:     # 조건에 맞지 않아 위에서 break가 걸리지 않은 경우
            rooms.append([[int(lv), name]])     # 새로운 방을 파야 함.
    
# 각 방 상태를 탐색하며 정원이 꽉 차있는 경우에는 started, 모자란 경우에는 waiting 출력한 후 각 방의 player들도 같이 출력
for room in rooms:
    if len(room) == m:
        print('Started!')
    else:
        print('Waiting!')
    room.sort(key=lambda x:x[1])     # 닉네임이 사전 순으로 앞선 player부터 출력해야 하므로 닉네임을 오름차순으로 정렬해 주었다.
    for player in room:
        print(player[0], player[1])

 

 

 

🙂 돌아보기

한 줄에 같이 주어지는 플레이어의 레벨과 닉네임은 각각 int형과 str형으로 처리해야 하기 때문에 형변환에 유의해야 했다.

또, 출력 시 닉네임을 기준으로 오름차순으로 출력해야 하는 부분도 꼭 확인하고 넘어가야 했다.

처음에 문제 자체를 이해하는 데 어려움이 있기도 하였다.