[BOJ] 1461 - 도서관

Sierra·2023년 2월 17일
0

[BOJ] Greedy

목록 보기
33/33
post-thumbnail

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

문제

세준이는 도서관에서 일한다. 도서관의 개방시간이 끝나서 세준이는 사람들이 마구 놓은 책을 다시 가져다 놓아야 한다. 세준이는 현재 0에 있고, 사람들이 마구 놓은 책도 전부 0에 있다. 각 책들의 원래 위치가 주어질 때, 책을 모두 제자리에 놔둘 때 드는 최소 걸음 수를 계산하는 프로그램을 작성하시오. 세준이는 한 걸음에 좌표 1칸씩 가며, 책의 원래 위치는 정수 좌표이다. 책을 모두 제자리에 놔둔 후에는 다시 0으로 돌아올 필요는 없다. 그리고 세준이는 한 번에 최대 M권의 책을 들 수 있다.

입력

첫째 줄에 책의 개수 N과, 세준이가 한 번에 들 수 있는 책의 개수 M이 주어진다. 둘째 줄에는 책의 위치가 주어진다. N과 M은 50보다 작거나 같은 자연수이다. 책의 위치는 0이 아니며, 절댓값은 10,000보다 작거나 같은 정수이다.

출력

첫째 줄에 정답을 출력한다.

예제 입출력

  • 예제 입력 1
7 2
-37 2 -6 -39 -29 11 -28
  • 예제 출력 1
131
  • 예제 입력 2
8 3
-18 -9 -4 50 22 -26 40 -45
  • 예제 출력 2
158
  • 예제 입력 3
6 2
3 4 5 6 11 -1
  • 예제 출력 3
29
  • 예제 입력 4
1 50
1
  • 예제 출력 4
1

Solution

package BOJ.Algorithms.Greedy;

import java.util.*;
import java.io.*;

class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int N = Integer.parseInt(st.nextToken());
        int M = Integer.parseInt(st.nextToken());

        int answer = 0;

        PriorityQueue<Integer> plusQueue = new PriorityQueue<>((p1, p2) -> p2 - p1);
        PriorityQueue<Integer> minusQueue = new PriorityQueue<>((p1, p2) -> p2 - p1);

        st = new StringTokenizer(br.readLine());

        for (int i = 0; i < N; i++) {
            int tmp = Integer.parseInt(st.nextToken());
            if (tmp > 0) {
                plusQueue.offer(tmp);
            } else {
                minusQueue.offer(tmp * (-1));
            }
        }

        int maxValue = 0;

        if (plusQueue.isEmpty()) {
            maxValue = minusQueue.peek();
        } else if (minusQueue.isEmpty()) {
            maxValue = plusQueue.peek();
        } else {
            maxValue = Math.max(plusQueue.peek(), minusQueue.peek());
        }

        while (!plusQueue.isEmpty()) {
            int tmp = plusQueue.poll();
            for (int i = 0; i < M - 1; i++) {
                plusQueue.poll();
                if (plusQueue.isEmpty()) {
                    break;
                }
            }
            answer += tmp * 2;
        }

        while (!minusQueue.isEmpty()) {
            int tmp = minusQueue.poll();
            for (int i = 0; i < M - 1; i++) {
                minusQueue.poll();
                if (minusQueue.isEmpty()) {
                    break;
                }
            }
            answer += tmp * 2;
        }

        answer -= maxValue;

        bw.write(String.valueOf(answer));
        bw.flush();
    }

}

이동거리를 최대한 적게 한다는 의미를 잘 생각 해 보아야 한다. 일단 양수 좌표와 음수 좌표를 각각 우선순위큐에 집어넣는다.
집어넣는 값은 절댓값으로 한다. 구하고자 하는 값은 걸음 수기 때문이다.

6 2
3 4 5 6 11 -1

예제 입출력 3번 예시를 한번 생각해보자.

가장 큰 값은 가장 마지막에 집어넣는다고 생각하면 편하다. 가장 크기 때문에 돌아오지 않는 것을 가정하면 가장 큰 걸음 수를 절약할 수 있기 때문이다.

즉 좌표 11의 책은 가장 마지막에 가져다 두면 된다.

그럼 6, 4, -1 이 두가지 좌표를 지나가는 겸, 나머지 책들도 하나씩 가져다가 집어넣으면된다. 즉 해당좌표를 왕복하므로 각 음수, 양수 별 우선순위 큐에서 값 하나를 꺼낸 후, 그 후 가져다 둘 책 M - 1개를 꺼낸다. 제일 먼저 꺼낸 값의 왕복 걸음수를 answer에 갱신하면 된다.

마지막으로 가장 큰 값은 왕복을 하는 값이 아니므로 제외한다.

profile
블로그 이전합니다 : https://swj-techblog.vercel.app/

0개의 댓글