[프로그래머스/C++] 호텔 방 배정

연성·2021년 8월 9일
0

코딩테스트

목록 보기
204/261

[프로그래머스/C++] 호텔 방 배정

1. 문제

[본 문제는 정확성과 효율성 테스트 각각 점수가 있는 문제입니다.]

"스노우타운"에서 호텔을 운영하고 있는 "스카피"는 호텔에 투숙하려는 고객들에게 방을 배정하려 합니다. 호텔에는 방이 총 k개 있으며, 각각의 방은 1번부터 k번까지 번호로 구분하고 있습니다. 처음에는 모든 방이 비어 있으며 "스카피"는 다음과 같은 규칙에 따라 고객에게 방을 배정하려고 합니다.

  1. 한 번에 한 명씩 신청한 순서대로 방을 배정합니다.
  2. 고객은 투숙하기 원하는 방 번호를 제출합니다.
  3. 고객이 원하는 방이 비어 있다면 즉시 배정합니다.
  4. 고객이 원하는 방이 이미 배정되어 있으면 원하는 방보다 번호가 크면서 비어있는 방 중 가장 번호가 작은 방을 배정합니다.

예를 들어, 방이 총 10개이고, 고객들이 원하는 방 번호가 순서대로 [1, 3, 4, 1, 3, 1] 일 경우 다음과 같이 방을 배정받게 됩니다.

전체 방 개수 k와 고객들이 원하는 방 번호가 순서대로 들어있는 배열 room_number가 매개변수로 주어질 때, 각 고객에게 배정되는 방 번호를 순서대로 배열에 담아 return 하도록 solution 함수를 완성해주세요.

2. 제한사항

  • k는 1 이상 10^12 이하인 자연수입니다.
  • room_number 배열의 크기는 1 이상 200,000 이하입니다.
  • room_number 배열 각 원소들의 값은 1 이상 k 이하인 자연수입니다.
  • room_number 배열은 모든 고객이 방을 배정받을 수 있는 경우만 입력으로 주어집니다.
    • 예를 들어, k = 5, room_number = [5, 5] 와 같은 경우는 방을 배정받지 못하는 고객이 발생하므로 이런 경우는 입력으로 주어지지 않습니다.

3. 풀이

  • 분리 집합 문제 분리 집합 기본 코드
  • 문제를 처음 보고 참 단순한 조건을 가진 문제라고 생각했다.
  • 하지만 조건으로 주어진 k의 범위가 참 마음에 들지 않았다.
  • k 범위 때문에 할 수 있는 풀이 방법이 제한되었다.
  • 기존의 분리 집합 문제와 똑같이 풀어주면 된다.
  • 단, k의 범위 때문에 배열로 풀 수 없고 연결을 처리해줄 자료구조로 map을 쓰면 된다.
  • 현재 방의 부모가 없다면
    • 현재 방에 손님을 투숙시키고 answer 배열에 현재 방 번호를 저장한다.
    • 현재 방과 다음 방(단순히 번호가 1큰 방이 아니라 번호가 1 큰 방의 부모)을 합집합한다.
  • 현재 방의 부모가 있다면
    • 부모를 찾아와 부모의 방에 손님을 투숙 시키고 answer 배열에 부모의 방 번호를 저장한다.
    • 부모의 방과 부모의 다음 방을 합집합한다.

코드 개선 작업

  for (long long room : room_number) {
    if (!m[room]) {
      answer.push_back(room);
      unionParent(m, room, room + 1);
    }
    else {
      room = findParent(m, room);
      answer.push_back(room);
      unionParent(m, room, room + 1);
    }
  }
  • 공통 부분을 모두 제거하고 if 문을 단순화 시켜준다.
    for (long long room : room_number) {
        if (m[room]) {
            room = findParent(m, room);
        }
        answer.push_back(room);
        unionParent(m, room, room + 1);
    }

4. 처음 코드와 달라진 점

  • 전부 long long으로 잘 써놓고 findParent의 x만 int로 썼다.
  • unionParent의 코드를 기존 코드를 쓰다보니 쓸데없는 코드가 있어서 삭제했다.

변경 전

void unionParent(map<long long, long long> &m, long long a, long long b) {
    a = findParent(m, a);
    b = findParent(m, b);
    
    if (a < b) m[a] = b;
    else m[b] = a;
}

변경 후

void unionParent(map<long long, long long> &m, long long a, long long b) {
    a = findParent(m, a);
    b = findParent(m, b);
    
    m[a] = b;
}

5. 코드

#include <string>
#include <vector>
#include <map>

using namespace std;

long long findParent(map<long long, long long> &m, long long x) {
    if (!m[x]) return x;
    else return m[x] = findParent(m, m[x]);
}

void unionParent(map<long long, long long> &m, long long a, long long b) {
    a = findParent(m, a);
    b = findParent(m, b);
    
    m[a] = b;
}

vector<long long> solution(long long k, vector<long long> room_number) {
    vector<long long> answer;
    map<long long, long long> m;
    
    for (long long room : room_number) {
        if (m[room]) {
            room = findParent(m, room);
        }
        
        answer.push_back(room);
        unionParent(m, room, room + 1);
    }
    return answer;
}

0개의 댓글