[Python] 백준 1966 프린터 큐 (Deque)

선주·2022년 1월 2일
1

Python PS

목록 보기
8/65
post-thumbnail

📌 문제

여러분도 알다시피 여러분의 프린터 기기는 여러분이 인쇄하고자 하는 문서를 인쇄 명령을 받은 ‘순서대로’, 즉 먼저 요청된 것을 먼저 인쇄한다. 여러 개의 문서가 쌓인다면 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번째로 인쇄되게 된다.

입력

첫 줄에 테스트케이스의 수가 주어진다. 각 테스트케이스는 두 줄로 이루어져 있다.

테스트케이스의 첫 번째 줄에는 문서의 개수 N(1 ≤ N ≤ 100)과, 몇 번째로 인쇄되었는지 궁금한 문서가 현재 Queue에서 몇 번째에 놓여 있는지를 나타내는 정수 M(0 ≤ M < N)이 주어진다. 이때 맨 왼쪽은 0번째라고 하자. 두 번째 줄에는 N개 문서의 중요도가 차례대로 주어진다. 중요도는 1 이상 9 이하의 정수이고, 중요도가 같은 문서가 여러 개 있을 수도 있다.

출력

각 테스트 케이스에 대해 문서가 몇 번째로 인쇄되는지 출력한다.

예제 입력

3
1 0
5
4 2
1 2 3 4
6 0
1 1 9 1 1 1

번역이 썩 매끄럽지 않아서 이해를 돕기 위해 그림을 그려보았다. 우선순위 큐에 따르면 빨간 색이 몇 번째로 인쇄되는지 구하면 되는 문제이다.

예제 출력

1
2
5


📌 풀이

코드

import sys
from collections import deque
input = sys.stdin.readline

tc = int(input())

for _ in range(tc):
    n, idx = map(int, input().split())
    q = deque(map(int, input().split()))
    idxq = deque(range(0, n))

    cnt = 0

    while q:
        if q[0] == max(q):
            cnt += 1
            q.popleft()
            if idxq.popleft() == idx:
                print(cnt)
                break
        else:
            q.rotate(-1)
            idxq.rotate(-1)

자료구조 설명

q.append(q.popleft()) 역할을 q.rotate(-1)로 수행할 수 있다. rotate(-1)은 원형 큐가 반시계방향으로 1칸 회전하고, rotate(1)은 시계방향으로 1칸 회전한다고 생각하면 된다. 따라서 rotate(-1)을 하면 맨 앞의 것을 pop해서 맨 뒤로 push하는 형태가 되는 것이다.

문제에서 원하는 기능은 구현했다. 다만 이렇게 한다면 본래 0번째 인덱스에 담겨 있던 값이 무엇이었는지 잃게 된다. 문제가 묻는 것은 '초기 상태의 0번째 인덱스에 담겨 있던 것이 몇 번째로 pop되는지'이므로, rotate될 때 초기 상태의 인덱스 정보를 잃으면 안 된다.

따라서 인덱스 정보를 담은 deque를 새로 만들었다. idxq = deque(range(0, n))으로! q의 인덱스가 idxq의 값이 되는 것이다. q가 rotate될 때 idxq도 rotate시킴으로써 초기 상태의 인덱스와 값이 함께 이동하도록 한다.


동작방식 설명

큐의 맨 앞에 있는 값이 현재 큐에서 가장 클 때 pop되므로, q[0]과 max(q)를 비교한다.

같다면 pop갯수를 나타내는 cnt를 1 증가시키고 pop한다. 물론 idxq에서도 같이 pop하고, 이때 이 pop된 값이 우리가 주시하고 있는 인덱스와 같다면 실행을 끝내며 몇번째로 pop된건지 cnt를 출력한다.

다르면 큐를 rotate(-1)시킨다.

실행 순서는 아래와 같다.

> 1
  6 0
  1 1 9 1 1 1
  
[1, 1, 9, 1, 1, 1]
[1, 9, 1, 1, 1, 1]
[9, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1]
[1, 1, 1, 1]
[1, 1, 1]
[1, 1]
break
> 1
  4 2
  1 2 3 4
  
[1, 2, 3, 4]
[2, 3, 4, 1]
[3, 4, 1, 2]
[4, 1, 2, 3]
[1, 2, 3]
[2, 3, 1]
[3, 1, 2]
break
profile
기록하는 개발자 👀

1개의 댓글

comment-user-thumbnail
2022년 9월 5일

코드를 제출해보면 정답이라고 나오는데, 궁금한 점이 있습니다.

idxq 는 현재 q에서 돌아가고 있는 값들이 처음에는 몇번째에 위치해 있었는지 나타내는 deque 이고, 처음부터 q와 같이 rotate되면서 이를 구현하는 것으로 이해했습니다.

하지만, q에서 pop을 통해서 빠져나가는 요소들이 있다면, idxq에서도 pop을 통해 같은 동작을 실행해주어야 하는 것 아닌가요?

q가 3개로 rotate되는 동안 idx는 4개 이상으로 rotate 되는 현상이 일어날 수 있을 것처럼 보여집니다.

혹시 이 부분 설명 가능하실까요?

답글 달기