[백준] 1966번 : 프린터 큐 - JAVA [자바]
1966번: 프린터 큐
여러분도 알다시피 여러분의 프린터 기기는 여러분이 인쇄하고자 하는 문서를 인쇄 명령을 받은 ‘순서대로’, 즉 먼저 요청된 것을 먼저 인쇄한다. 여러 개의 문서가 쌓인다면 Queue 자료구조에
www.acmicpc.net
-
문제

- 알고리즘 [접근 방법]
이 번 문제는 위에서 말한 내용을 그대로 큐로 구현만해주면 되는 문제라 그리 어렵지 않게 풀 수 있을 것이다.
문제를 이해해보자면 이렇다.
큐에 프린트 할 문서들이 배치되어있을 때, '중요도'가 높은 것 부터 뽑아야한다는 것이다.
즉, 맨 앞의 문서보다 중요도가 높은 문서가 있을 경우 맨 앞의 문서를 맨 뒤로 보내고, 이를 반복하면서 가장 중요도가 높은 문서가 맨 앞에 배치되도록 해야한다는 것.
이러한 원리로 문서를 중요도가 높은 것 부터 프린트할 때 맨 처음에 찾고자 하던 M번째 문서는 몇 번째로 뽑히는지를 찾아내야하는 것이다.
예로들어 0번째부터 4개의 문서의 중요도가 순서대로 {4, 2, 3, 5}로 주어졌다고 가정하고 두 번째 문서(중요도 : 3)가 몇 번째로 출력되는지를 알아본다고 가정해보자.

위와 같이 알고리즘을 구성하면 된다.
다만, 큐에서 탐색할 때 처음 poll() 된 원소가 가장 큰 경우와, 아닌 경우의 루트가 다르다.
만약 처음 poll() 된 원소가 가장 큰 경우는 해당 원소의 첫 위치가 M이랑 같은지를 비교해야하고,
만약 큐에 poll() 된 원소보다 중요도가 큰 원소가 있는 경우에는 그 원소 앞에 있던 원소들을 뒤로 보낸 뒤, 다시 첫 원소를 poll()하여 비교를 큐 안에 poll() 된 원소보다 중요도가 큰 원소가 있는지를 검사해야 한다.
그렇기 때문에 두 번째 경우에는 해당 원소를 M이랑 같은지 검사할 필요가 없기 때문에 이 분기를 위해서 플래그(Flag) 변수를 하나 두는 것이 좋다.
글로만 설명하면 무슨 말인지 모를 수도 있으니 밑에 코드를 보면서 이해해보도록 해보자.
- 2가지 방법을 사용하여 풀이한다.
이 번에는 Scanner와 BufferedReader 입력만 달리하여 풀이 할 것이다.
출력은 모두 StringBuilder을 사용한다.
1. Scanner
2. BufferedReader
- 풀이
- 방법 1 : [Scanner]
import java.util.Scanner; import java.util.LinkedList; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); StringBuilder sb = new StringBuilder(); int T = in.nextInt(); // 테스트 케이스 while (T-- > 0) { int N = in.nextInt(); int M = in.nextInt(); LinkedList<int[]> q = new LinkedList<>(); // Queue로 활용 할 연결리스트 for (int i = 0; i < N; i++) { // {초기 위치, 중요도} q.offer(new int[] { i, in.nextInt() }); } int count = 0; while (!q.isEmpty()) { // 한 케이스에 대한 반복문 int[] front = q.poll(); // 가장 첫 원소 boolean isMax = true; // front 원소가 가장 큰 원소인지를 판단하는 변수 // 큐에 남아있는 원소들과 중요도를 비교 for(int i = 0; i < q.size(); i++) { // 처음 뽑은 원소보다 큐에 있는 i번째 원소가 중요도가 클 경우 if(front[1] < q.get(i)[1]) { // 뽑은 원소 및 i 이전의 원소들을 뒤로 보낸다. q.offer(front); for(int j = 0; j < i; j++) { q.offer(q.poll()); } // front원소가 가장 큰 원소가 아니였으므로 false를 하고 탐색을 마침 isMax = false; break; } } // front 원소가 가장 큰 원소가 아니였으므로 다음 반복문으로 넘어감 if(isMax == false) { continue; } // front 원소가 가장 큰 원소였으므로 해당 원소는 출력해야하는 문서다. count++; if(front[0] == M) { // 찾고자 하는 문서라면 해당 테스트케이스 종료 break; } } sb.append(count).append('\n'); } System.out.println(sb); } }
가장 기본적인 방법이라 할 수 있겠다.
앞서 말했듯이 front 값이 가장 큰 값이냐, 아니냐에 따라 출력해야 하는 원소인지 아닌지가 갈리기 때문에 isMax 변수를 두었다.
아무래도 반복문이 3중이다보니 조금은 헷갈릴 수 있지만 최대한 주석으로 설명을 해놓았으니 조금만 이해보도록 하자. 이해만하면 어렵지 않다.
그리고 큐의 경우는 중간 탐색(get()) 을 사용해야하므로 LinkedList를 사용했다. 물론, LinkedList도 Queue를 구현하기 때문에 offer, poll 같은 메소드도 사용할 수 있다. offer 대신 add, poll 대신 remove를 사용해도 무방하지만, 큐 문제인만큼 일관성있게 offer와 poll을 사용했다.
- 방법 2 : [BufferedReader]
입력 방법을 Scanner 대신 BufferedReader 을 사용하여 풀이하는 방법이다. 단, BufferedReader 는 문자열을 한 줄로 읽기 때문에 N과 M을 구분하기 위해 공백을 기준으로 문자열을 분리해주어야하니 StringTokenizer 을 사용하여 풀도록 하겠다.
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.util.StringTokenizer; import java.util.LinkedList; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringBuilder sb = new StringBuilder(); int T = Integer.parseInt(br.readLine()); // 테스트 케이스 while (T-- > 0) { StringTokenizer st = new StringTokenizer(br.readLine()); int N = Integer.parseInt(st.nextToken()); int M = Integer.parseInt(st.nextToken()); LinkedList<int[]> q = new LinkedList<>(); // Queue로 활용 할 연결리스트 st = new StringTokenizer(br.readLine()); for (int i = 0; i < N; i++) { // {초기 위치, 중요도} q.offer(new int[] { i, Integer.parseInt(st.nextToken()) }); } int count = 0; // 출력 횟수 while (!q.isEmpty()) { // 한 케이스에 대한 반복문 int[] front = q.poll(); // 가장 첫 원소 boolean isMax = true; // front 원소가 가장 큰 원소인지를 판단하는 변수 // 큐에 남아있는 원소들과 중요도를 비교 for(int i = 0; i < q.size(); i++) { // 처음 뽑은 원소보다 큐에 있는 i번째 원소가 중요도가 클 경우 if(front[1] < q.get(i)[1]) { // 뽑은 원소 및 i 이전의 원소들을 뒤로 보낸다. q.offer(front); for(int j = 0; j < i; j++) { q.offer(q.poll()); } // front원소가 가장 큰 원소가 아니였으므로 false를 하고 탐색을 마침 isMax = false; break; } } // front 원소가 가장 큰 원소가 아니였으므로 다음 반복문으로 넘어감 if(isMax == false) { continue; } // front 원소가 가장 큰 원소였으므로 해당 원소는 출력해야하는 문서다. count++; if(front[0] == M) { // 찾고자 하는 문서라면 해당 테스트케이스 종료 break; } } sb.append(count).append('\n'); } System.out.println(sb); } }
알고리즘은 완전히 같이 때문에 별달리 설명할 것은 없다.
- 성능

채점 번호 : 26003402 - 방법 2 : BufferedReader
채점 번호 : 26003393 - 방법 1 : Scanner
입력의 경우는 확실히 Scanner 보다는 BufferedReader 가 빠른 걸 볼 수 있다.
- 정리
이 번 문제는 크게 어려운 점이 없었을 것이다. 주어진 문제를 그대로 옮기면 되기 때문에 분기문만 조심해서 쓸 거 외에는 별달리 설명할 것도 없었다.
풀이 방법이야 필자가 말 한 것이 정답은 아니니 다양하게 여러분만의 것으로 만들어 풀어보셔도 좋을 것 같다.
'JAVA - 백준 [BAEK JOON] > 큐, 덱' 카테고리의 다른 글
[백준] 1021번 : 회전하는 큐 - JAVA [자바] (0) | 2021.02.27 |
---|---|
[백준] 10866번 : 덱 - JAVA [자바] (8) | 2021.02.19 |
[백준] 11866번 : 요세푸스 문제 0 - JAVA [자바] (10) | 2021.01.23 |
[백준] 2164번 : 카드2 - JAVA [자바] (4) | 2020.12.19 |
[백준] 18258번 : 큐 2 - JAVA [자바] (5) | 2020.12.13 |
댓글을 사용할 수 없습니다.