프린터 큐 [1966번]

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

입력

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

출력

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

생각해볼점

큐(Queue)

위키피디아 링크
앞서 본 적 있는 스택과 반대되는 개념이다.
First in Last Out이었던 스택과 달리 큐는 First in First Out이다. 즉, 먼저 들어가면 먼저 나온다. 일렬로 줄을 선 경우를 연상하면 정확하게 이해할 수 있다.

이 문제의 경우

진짜 큐처럼 작동하려면 배열을 앞쪽부터 탐색해가며 찾은 수가 가장 큰 수가 아닐 경우, 배열에서 제거 한 후 배열 가장 맨 뒤에 다시 놓는 작업을 반복해야한다.
하지만 이렇게 할 경우 배열을 계속 변경시켜주는 작업이 반복되며 시간과 메모리를 소모하게되므로, 배열은 그대로 두되 현재 가리키고있는 지점(코드에서는 point로 지정하였다)을 변화시켜가며 큐의 구조대로 작동하도록 하였다.

코드 구현

#include <stdio.h>
#include <stdlib.h>

int main()
{
	int	test_num, doc_num, what_num, max, doc_idx, *doc, point = 0, count = 1;
	
	scanf("%d", &test_num);
	
	while (test_num-- > 0)
	{
		scanf("%d %d", &doc_num, &what_num);
		doc = (int *)malloc(doc_num * sizeof(int));

		doc_idx = -1;
		while (++doc_idx < doc_num)
			scanf("%d", &doc[doc_idx]);

		point = 0;
		count = 1;
		while (1)
		{
			max = 0;
			doc_idx = -1;
			while (++doc_idx < doc_num)  // 우선 배열을 한바퀴 돌며 가장 큰 중요도를 찾는다.
			{
				if (max < doc[doc_idx])
					max = doc[doc_idx];
			}
			
			while (doc[point] != max)  
				point = (point + 1) % doc_num;
			// 배열의 현재 지점이 max값이 아닌 경우, 지점을 다음 원소로 옮긴다.
			// 마지막 원소일 경우 다시 가장 앞의 원소로 이동한다. 지나간 원소가 다시 큐의 맨 마지막으로 들어올 것이기 때문에 가능한 동작이다.

			if (point != what_num)	// 현재 지점이 max값이라면 0으로 만들며 인쇄한다. 프린터가 한번 인쇄한 것이므로 카운트를 늘린다.
			{
				doc[point] = 0;
				count++;
			}
			else
				break;
		}
		printf("%d\n", count); // 몇 번째 인쇄인지 출력한다. 
		free(doc);
	}

	return (0);
}