1966. 프린터 큐
https://www.acmicpc.net/problem/1966
걸린 시간: 20m32s
문제
여러분도 알다시피 여러분의 프린터 기기는 여러분이 인쇄하고자 하는 문서를 인쇄 명령을 받은 ‘순서대로’, 즉 먼저 요청된 것을 먼저 인쇄한다. 여러 개의 문서가 쌓인다면 Queue 자료구조에 쌓여서 FIFO - First In First Out - 에 따라 인쇄가 되게 된다. 하지만 상근이는 새로운 프린터기 내부 소프트웨어를 개발하였는데, 이 프린터기는 다음과 같은 조건에 따라 인쇄를 하게 된다.
- 현재 Queue의 가장 앞에 있는 문서의 ‘중요도’를 확인한다.
- 나머지 문서들 중 현재 문서보다 중요도가 높은 문서가 하나라도 있다면, 이 문서를 인쇄하지 않고 Queue의 가장 뒤에 재배치 한다. 그렇지 않다면 바로 인쇄를 한다.
예를 들어 Queue에 4개의 문서(A B C D)가 있고, 중요도가 2 1 4 3 라면 C를 인쇄하고, 다음으로 D를 인쇄하고 A, B를 인쇄하게 된다.
여러분이 할 일은, 현재 Queue에 있는 문서의 수와 중요도가 주어졌을 때, 어떤 한 문서가 몇 번째로 인쇄되는지 알아내는 것이다. 예를 들어 위의 예에서 C문서는 1번째로, A문서는 3번째로 인쇄되게 된다.
문제 접근 방법
일단 큐 + 중요도이기 때문에 바로 우선순위 큐를 떠올렸다.
C++ STL의 우선순위 큐를 살펴보니 <value, priority>
가 아니라 값 하나만을 받고 이를 토대로 바로 정렬을 해버려서 입력 순서를 지켜야하는 이번 문제에서는 사용할 수 없을 것 같았다.
하지만 일반적인 큐를 사용하자니 max
를 구할때마다 반복하기에는 비효율적일 것 같아서, 공간을 좀 더 쓰는 방향으로 큐는 입력 순서를 지키기 위해, 그리고 우선순위 큐를 사용해서 max
를 파악하는 방향으로 다가갔다.
풀이
1#include <bits/stdc++.h> 2using namespace std; 3 4#define ios cin.tie(NULL), ios_base::sync_with_stdio(false) 5#define endl '\n' 6 7int main(){ 8 ios; 9 int t; 10 cin >> t; 11 12 while(t--) { 13 list<pair<int, int> > q; 14 priority_queue<int> pq; 15 int cnt = 1; 16 int n, m; 17 cin >> n >> m; 18 19 for(int i=0; i<n; ++i) { 20 int val; cin >> val; 21 q.push_back(make_pair(val, i)); 22 pq.push(val); 23 } 24 25 while(true) { 26 if(q.front().first < pq.top()) { 27 q.push_back(q.front()); 28 q.pop_front(); 29 } else { 30 if(q.front().second == m) break; 31 q.pop_front(); 32 pq.pop(); 33 ++cnt; 34 } 35 } 36 37 cout << cnt << endl; 38 } 39 return 0; 40}
시간 복잡도
- 우선순위 큐의
push
- O(logN), N은 우선순위 큐의 크기 - 프린터 전부 출력 - O(2M), M = 문서 개수
- 우선순위 큐의
pop
- O(2logN), N은 우선순위 큐의 크기
- 우선순위 큐의
- 최종 시간 복잡도: O(logN + 2M・2logN) => O(M・logN)
공간 복잡도
- M개의 문서 저장
pair<doc, index>
- O(2M), M = 문서 개수 - M개 문서의 중요도 우선순위 큐에 저장 - O(M)
- 최종 공간 복잡도: O(3M) => O(M)