문제 설명
카카오에서는 무료 셔틀버스를 운행하기 때문에 판교역에서 편하게 사무실로 올 수 있다. 카카오의 직원은 서로를 '크루'라고 부르는데, 아침마다 많은 크루들이 이 셔틀을 이용하여 출근한다.
이 문제에서는 편의를 위해 셔틀은 다음과 같은 규칙으로 운행한다고 가정하자.
- 셔틀은 09:00부터 총 n회 t분 간격으로 역에 도착하며, 하나의 셔틀에는 최대 m명의 승객이 탈 수 있다.
- 셔틀은 도착했을 때 도착한 순간에 대기열에 선 크루까지 포함해서 대기 순서대로 태우고 바로 출발한다. 예를 들어 09:00에 도착한 셔틀은 자리가 있다면 09:00에 줄을 선 크루도 탈 수 있다.
일찍 나와서 셔틀을 기다리는 것이 귀찮았던 콘은, 일주일간의 집요한 관찰 끝에 어떤 크루가 몇 시에 셔틀 대기열에 도착하는지 알아냈다. 콘이 셔틀을 타고 사무실로 갈 수 있는 도착 시각 중 제일 늦은 시각을 구하여라.
단, 콘은 게으르기 때문에 같은 시각에 도착한 크루 중 대기열에서 제일 뒤에 선다. 또한, 모든 크루는 잠을 자야 하므로 23:59에 집에 돌아간다. 따라서 어떤 크루도 다음날 셔틀을 타는 일은 없다.
제한 사항
셔틀 운행 횟수 n, 셔틀 운행 간격 t, 한 셔틀에 탈 수 있는 최대 크루 수 m, 크루가 대기열에 도착하는 시각을 모은 배열 timetable이 입력으로 주어진다.
- 0 < n ≦ 10
- 0 < t ≦ 60
- 0 < m ≦ 45
- timetable은 최소 길이 1이고 최대 길이 2000인 배열로, 하루 동안 크루가 대기열에 도착하는 시각이 HH:MM 형식으로 이루어져 있다.
- 크루의 도착 시각 HH:MM은 00:01에서 23:59 사이이다.
풀이
자료구조를 잘 짜면 쉽게 풀 수 있는 문제이다.
문제의 핵심은 최대한 늦게 줄을 서는 것이다.
크루들이 줄을 서는 시간은 셔틀을 탈 수 있다는 보장이 없다.
즉, 크루들이 줄을 서는 시간보다 1분 빨리 선다고 답이 되는 것은 아니다.
우선, 셔틀을 타는 크루와 그렇지 못한 크루를 나눌 필요가 있다.
그러고 나서 셔틀을 타는 크루 중 가장 늦게 온 크루보다 1분 일찍 줄을 서면 된다.
이때, 한가지 예외사항이 있는데 만약 셔틀에 자리가 남아있다면 셔틀이 도착하는 시간에 줄을 서는 것이 가장 늦게 오는 방법이다.
이 부분만 체크하면 문제는 간단하게 풀린다.
정리하자면, 크루들의 도착시간을 정렬한 뒤 셔틀에 탈 수 있는 크루들을 시간대별로 저장한다.
이후, 마지막 셔틀의 자리가 남았다면 해당 셔틀이 도착한 시간을 선택하고 자리가 남아있지 않다면 가장 늦게 온 크루보다 1분 먼저 도착하면 된다.
문제의 핵심은 셔틀을 타는 크루와 그렇지 않은 크루를 나눠 자료구조에 저장하는 부분인 듯하다.
셔틀이 도착하는 시간과 그 시간에 셔틀을 타는 크루가 도착한 시간을 모두 관리하고 싶었기 때문에 다음과 같은 자료구조를 사용하였다.
map<int, vector<int>> seat;
하지만, 크루를 셔틀에 태울 때 이 자료구조가 초기화되어 있지 않으면 태울 수 없다.
이 부분에 대한 초기화를 고민하였는데 다음과 같이 진행하였다.
int currentTime = Convert("09:00");
for(int i = 0; i < n; i++)
{
seat[currentTime+(i*t)];
}
map은 해당 key에 대해 조회나 삽입 등 연산을 하는 순간 메모리가 할당된다.
이러한 점을 이용하여 셔틀 도착시간을 초기화하였다.
그리고 모든 시간을 분단위로 환산하여 관리한 뒤, 다시 스트링으로 바꿔 정답을 제출하였다.
스트링으로 모든 부분을 관리하면 -1 하는 시점에서 복잡한 연산이 필요하기 때문이다.
전체 코드
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
#include <map>
using namespace std;
int Convert(string time)
{
return ((time[0] - '0') * 10 + time[1] - '0') * 60 + (time[3] - '0') * 10 + (time[4] - '0');
}
string timeToString(int time)
{
string result;
int hour = time / 60;
time -= hour * 60;
if(hour / 10 < 1) result += "0";
result += to_string(hour);
result += ":";
if(time / 10 < 1) result += "0";
result += to_string(time);
return result;
}
bool cmp(string& a, string& b)
{
int timeA = Convert(a);
int timeB = Convert(b);
return timeA < timeB;
}
string solution(int n, int t, int m, vector<string> timetable) {
string answer = "";
int currentTime = Convert("09:00");
map<int, vector<int>> seat;
sort(timetable.begin(), timetable.end(), cmp);
for(int i = 0; i < n; i++)
{
seat[currentTime+(i*t)];
}
for(auto crew : timetable)
{
int time = Convert(crew);
for(auto itr = seat.begin(); itr != seat.end(); itr++)
{
if(time <= itr->first && itr->second.size() < m)
{
itr->second.push_back(time);
break;
}
}
}
if(seat.rbegin()->second.size() < m)
{
answer = timeToString(seat.rbegin()->first);
}
else
{
answer = timeToString(seat.rbegin()->second[seat.rbegin()->second.size()-1]-1);
}
return answer;
}