2 분 소요

셔틀버스 (프로그래머스 Level 3)

https://school.programmers.co.kr/learn/courses/30/lessons/17678

최근에 이진탐색으로 문제를 푸는 방식과 그 필요성에 대하여 다시금 생각할 수 있었다

  • ‘최적화문제’를 ‘결정문제’로 만들 수 있다면, 그 문제는 이진탐색으로 풀 수 있다
  • 최적화 문제 : 조건을 만족하는 특정한 값 ‘x’를 구하는 문제
  • 결정 문제 : 특정한 값 x 가 조건을 만족하는지를 확인하는 문제
    (이전에 dp 문제를 이진탐색으로 판단하였으나,
    알고 보니 특정값 ‘x’뿐 아니라 다른 변수의 값을 고려할 필요가 있었다)
  • 문제의 ‘상한’과 ‘하한’을 통해 ‘중간값’을 구할 수 있는지 확인하기

이번 문제인 경우
특정한 ‘시간’을 구하면 되는 문제이며
그 하한값과 상한값이 적은 편이기에 이진탐색으로 풀 수 있었다

Code

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

using namespace std;

int getTimeValue(string str)
{
    int hour = (str[0] - '0') * 10 + (str[1] - '0');
    int minu = (str[3] - '0') * 10 + (str[4] - '0');

    return hour * 60 + minu;
}

const int startTime = getTimeValue("09:00");

string getTimetoValue(int timeValue)
{
    int hour = timeValue / 60;
    int min = timeValue - hour * 60;

    string strHour = to_string(hour);
    if (strHour.size() == 1)
        strHour = "0" + strHour;
    string strMin = to_string(min);
    if (strMin.size() == 1)
        strMin = "0" + strMin;

    string ret = strHour + ":" + strMin;
    return ret;
}

bool isRightTime(int n, int t, int m, map<int, int> times,const vector<int>& bus, int timeValue)
{
    int fullCount = n * m; // 버스에 타는 사람의 총 량

    for (int i = 0; i < n; i++)
    {
        int nowTime = bus[i];
        int nowCount = 0;

        // 나도 탈 수 있는 시간
        if (timeValue <= nowTime &&
            fullCount == 0)
        {
            // 이미 자리 꽉참
            return false;
        }

        for (auto& a : times)
        {
            // 탈 수 있는 시간이다
            if (nowTime >= a.first)
            {
                // 근데 내가 더 빨리 왔다
                if (timeValue < a.first &&
                    nowCount < m)
                {
                    return true;
                }

                if (nowCount + a.second > m)
                {
                    a.second -= (m - nowCount);
                    nowCount = m;
                    break;
                }
                else
                {
                    nowCount += a.second;
                    a.second = 0;
                    if (nowCount == m)
                        break;
                }
            }
            else
            {
                break;
            }
        }

        if (timeValue <= nowTime &&
            nowCount < m)
        {
            return true;
        }

        fullCount -= m;
    }

    return false;
}

string solution(int n, int t, int m, vector<string> timetable) {
    string answer = "";
    map<int,int> times;
    vector<int> bus;

    int start = startTime;
    for (int i = 0; i < n; i++)
    {
        bus.push_back(start + t * i);
    }

    for (string str : timetable)
    {
        int timeValue = getTimeValue(str);
        times[timeValue]++;
    }

    int low = 0;
    int high = getTimeValue("23:59");

    while (low < high)
    {
        int mid = (low + high) / 2;
        if (mid == low)
            break;

        // 탈 수 있는 시간 중 가장 늦은값 구하기
        if (isRightTime(n, t, m, times,bus, mid))
        {
            low = mid;
        }
        else // 중간 값이 탈 수 없는 시간이니 아래로 낮춘다
        {
            high = mid;
        }
    }

    answer = getTimetoValue(low);
    return answer;
}

댓글남기기