알고리즘 문제풀이/프로그래머스
[프로그래머스/Level 4] 무지의 먹방 라이브
노력의천재
2021. 8. 21. 16:00
https://programmers.co.kr/learn/courses/30/lessons/42891
코딩테스트 연습 - 무지의 먹방 라이브
programmers.co.kr
카카오 기출
시간이 적게 걸리는 음식부터 확인하는 그리디 접근 방식으로 해결한다. (우선순위 큐를 이용)
[3, 1, 2] 3개의 음식이 있고 k가 5초라고 가정해보자
1. 가장 적게 걸리는 음식인 2번 음식을 빼는데, 음식이 3개 남아 있으므로 3(남은 음식의 개수) x 1(2번 음식을 먹는 시간) = 3을 빼준다. 이는 2번 음식을 다 먹기 위해 3초가 걸린다는 의미다. 결국 전체 남은 시간은 5 - 3 = 2초가 된다.
2. 남은 음식중에 가장 적게 걸리는 음식은 3번 음식을 빼야하는데, 전체 음식이 2개 남아 있으므로 2(남은 음식의 개수) x 2(3번 음식을 먹는 시간) = 4를 빼줘야 한다. 그러나 현재 남은 시간이 2초인데, 이는 4보다 작으므로 빼지 않는다.
3. 그러므로, 다음으로 먹어야 할 음식의 번호를 찾아서 출력해야 한다. 매초 먹어야 할 음식들을 나열하고 전체 남은 시간이 2초이므로, 3번째 음식의 번호를 출력하면 된다.
(3, 1) -> (2, 3) -> (3, 1) : 1번 음식을 출력
#include <string>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
int solution(vector<int> food_times, long long k) {
long long sum = 0;
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > pq;
vector<pair<int, int> > v;
for(int i = 0; i < food_times.size(); i++) {
sum += food_times[i];
}
// 전체 음식을 먹는 시간보다 k가 크거나 같다면 -1 (남은 음식이 없기 때문에)
if(sum <= k) return -1;
for(int i = 0; i < food_times.size(); i++) {
pq.push({ food_times[i], i + 1 });
}
sum = 0; // 먹기 위해 사용한 시간
long long prev = 0; // 직전에 다 먹은 시간
long long len = food_times.size(); // 남은 음식 개수
// summary + (현재의 음식 시간 - 이전 음식 시간) * 현재 음식 개수와 k 비교
while(sum + (pq.top().first - prev) * len <= k) {
int now = pq.top().first;
pq.pop();
sum += (now - prev) * len;
len--; // 다 먹은 음식 제외
prev = now; // 이전 음식 시간 재설정
}
// 우선순위 큐에 남은 값을 벡터에 옮기기
while(!pq.empty()) {
v.push_back({ pq.top().second, pq.top().first });
pq.pop();
}
// 음식의 번호 순서를 기준으로 오름차순 정렬
sort(v.begin(), v.end());
return v[(k - sum) % len].first;
}