Optimal Solution

[백준, C++] 20006 - 랭킹전 대기열 본문

알고리즘

[백준, C++] 20006 - 랭킹전 대기열

ICE_MAN 2023. 8. 31. 20:30
728x90

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

 

20006번: 랭킹전 대기열

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

www.acmicpc.net

 

문제 분석

플레이어가 방을 찾으러 들어가야 한단다. 근데 플레이어의 레벨이 방장의 레벨 +- 10의 범위 안에 있어야 방에 입장할 수 있단다(하긴 뭐 무작정 들어갈 수 있으면 그게 랭크게임인가). 당연하게도 방이 꽉 차면 레벨 조건이 맞아도 들어갈 수 없다. 플레이어가 들어갈 수 있는 방이 없는 경우에는 자신이 직접 방장이 된다.

 

이런 식으로 해서 플레이어가 주어졌을 때, 여러 방이 생길테고, 어떤 방은 정원이 차서 게임을 시작할거고 어떤 방은 정원이 안 차서 대기할 것이다. 그러면 방이 생성된 순서대로 방의 상태(Started or Waiting)와, 해당 방에 있는 플레이어의 레벨, 닉네임을 닉네임 사전순으로 출력하면 문제를 해결할 수 있다.

 

코드

#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

struct Player {
    int level;
    string nickname;

    Player(int level, string nickname) {
        this->level = level;
        this->nickname = nickname;
    }
};

struct Room {
    int level;
    vector<Player> players;

    Room(int level, Player roomOwner) {
        this->level = level;
        this->players = vector<Player>();
        this->players.push_back(roomOwner);
    } 
};

int p, m;
int l;
string n;
vector<Room> rooms;

bool compare(Player player1, Player player2) {
    return player1.nickname < player2.nickname;
}

void addPlayer(Player player) {
    for (int i = 0; i < rooms.size(); i++) {
        if (rooms[i].level + 10 >= player.level && rooms[i].level - 10 <= player.level && rooms[i].players.size() < m) {
            rooms[i].players.push_back(player);
            return;
        }
    }

    rooms.push_back(Room(l, player));
}

void printResult() {
    for (Room room : rooms) {
        if (room.players.size() == m) {
            cout << "Started!\n";
        } else {
            cout << "Waiting!\n";
        }

        sort(room.players.begin(), room.players.end(), compare);
        for (Player player : room.players) {
            cout << player.level << " " << player.nickname << "\n";
        }
    }
}

int main() {
    cin.tie(NULL);
    ios::sync_with_stdio(false);

    cin >> p >> m;

    for (int i = 0; i < p; i++) {
        cin >> l >> n;
        addPlayer(Player(l, n));
    }

    printResult();
    return 0;
}

 

코드 설명

원래 알고리즘 풀 때 굳이 함수를 잘 나누지 않는 편이었고, 자료형도 굳이 구조체나 클래스로 정의하지 않고 pair를 무지성으로 남발했는데, 딱히 좋은 습관은 아닌 것 같단 생각이 들었다. 개발할 때는 변수명 하나도 그렇게 세심하게 고민하고 또 고민하는데, 왜 알고리즘은 대충 짜지 하는 생각이 들기도 했고, 무엇보다 내가 옛날에 짠 코드를 나조차도 이해를 못하는 걸 보니 좀 '공들여' 짜야겠다고 생각했다.

 

각설하고, 두 개의 구조체 Player와 Room을 만들었다. 나는 이 두 구조체를 활용해 문제를 풀었다.

사실 알고리즘을 설명할 것도 없는데, 이 문제는 내가 만든 단 2개의 메서드로 풀린다. addPlayer()와 printResult()이다.

 

addPlayer() 메서드는 Player를 인자로 받아서, 해당 Player가 들어갈 수 있는 Room이 있는지를 찾는다. 들어갈 수 있는 Room이 있다면 넣어주고, 그렇지 않다면 Room을 새로 생성하는 메서드이다. Player를 Room에 넣을 수 있는 조건은 별로 까다롭지 않기 때문에 굳이 설명하지 않는다.

 

printResult() 메서드는 Room에 정원이 가득 찼는지 여부를 확인해서 Started 나 Waiting 중 하나를 출력을 먼저 한다. 그리고 문제 본문의 출력 설명 중 닉네임은 '사전순으로 앞서는 플레이어부터' 출력하라고 했는데 이 부분을 놓쳐서 처음에 제출했을 때 틀렸습니다 라고 떴다. 문제를 오늘도 대충 읽었다. 사전순으로 앞서는 플레이어부터 출력하기 위해 Room 안에 있는 players 벡터를 정렬해줬다. compare 메서드는 직접 작성했다.

 

난이도가 실버 2라고 되어있는데 이게 왜 실버 2인지 잘 모르겠다. 단순한 구현인데 . . . 

728x90