Link
https://www.acmicpc.net/problem/17612
Detail
문제에 적힌 내용을 그대로 시뮬레이션 해보는 과정에서 “빨리 끝난 계산대부터” 손님을 보내서 계산하고, 마지막 정답도 “먼저 계산이 끝난 순서대로” 처리한다는 내용에서 [우선순위 큐](Priority Queue) 를 사용하면 으로 시간 내에 풀 수 있다고 생각되었다.
세 개의 자료구조
Waiting
vector<pair<int, int>> waiting
대기열에 서있는 손님들의 목록을 배열에 저장한다.
Cashiers
// {last_time, number}
priority_queue<
pair<int, int>,
deque<pair<int, int>>,
greater<>
> cashiers;
{계산이 끝날 시각, 계산대의 번호} 를 오름차순으로 저장하는 우선순위 큐다. 여기에 매번 손님이 계산하러 갈 때마다 last_time을 갱신시켜 top에 항상 다음 계산대가 위치하도록 한다. “두 계산기가 모두 계산가능할경우, 번호가 작은 순서대로 손님을 배정한다” 라는 규칙에 위배되지 않도록 구조가 짜여있다.
finish_quque
priority_queue<
tuple<int, int, int>,
vector<tuple<int, int, int>>,
greater<>
> finish_queue;
{계산이 끝난 시각, -계산대 번호, 손님 id} 순서로 저장하는 우선순위 큐다. 계산이 끝난 순서대로 확인하되, 시간이 같은 경우에 계산대 번호가 큰 손님부터 정답에서 계산해야 하므로 계산대 번호에 -1을 곱하여 두번째 요소로 넣어서 연산한다.
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
int n, k;
cin >> n >> k;
// {id, time}
vector<pair<int, int>> waiting;
// {last_time, number}
priority_queue<
pair<int, int>,
deque<pair<int, int>>,
greater<>
> cashiers;
// { finish_time, -cashier_id, customer_id }
priority_queue<
tuple<int, int, int>,
vector<tuple<int, int, int>>,
greater<>
> finish_queue;
// init
// customers
for (int i = 0; i < n; i++) {
int id, duration;
cin >> id >> duration;
waiting.emplace_back(id, duration);
}
// simulation
// first k customers
for (int cashier_id = 0; cashier_id < k; cashier_id++) {
cashiers.emplace(0, cashier_id);
}
for (int i = 0; i < n; i++) {
auto [id, duration] = waiting[i];
auto [last_time, number] = cashiers.top(); cashiers.pop();
int finish_time = last_time + duration;
finish_queue.emplace(finish_time, -number, id);
cashiers.emplace(finish_time, number);
}
ll r = 1;
ll answer = 0;
while (not finish_queue.empty()) {
auto [finish_time, cashier_id, customer_id] = finish_queue.top(); finish_queue.pop();
//cout << finish_time << " " << cashier_id << " " << customer_id << endl;
answer += (r++) * (ll)customer_id;
}
cout << answer << endl;
}