euisblue
1966. 프린터 큐

https://www.acmicpc.net/problem/1966

걸린 시간: 20m32s

문제

여러분도 알다시피 여러분의 프린터 기기는 여러분이 인쇄하고자 하는 문서를 인쇄 명령을 받은 ‘순서대로’, 즉 먼저 요청된 것을 먼저 인쇄한다. 여러 개의 문서가 쌓인다면 Queue 자료구조에 쌓여서 FIFO - First In First Out - 에 따라 인쇄가 되게 된다. 하지만 상근이는 새로운 프린터기 내부 소프트웨어를 개발하였는데, 이 프린터기는 다음과 같은 조건에 따라 인쇄를 하게 된다.

  1. 현재 Queue의 가장 앞에 있는 문서의 ‘중요도’를 확인한다.
  2. 나머지 문서들 중 현재 문서보다 중요도가 높은 문서가 하나라도 있다면, 이 문서를 인쇄하지 않고 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)