본문 바로가기
PS/BOJ

[자바] 백준 11912 - 격자 보존하기 (java)

by Nahwasa 2023. 8. 11.

문제 : boj11912

 

 

필요 알고리즘

  • 그리디 알고리즘
    • 규칙만 찾으면 쉽게 접근 가능하다.

※ 제 코드에서 왜 main 함수에 로직을 직접 작성하지 않았는지, 왜 Scanner를 쓰지 않고 BufferedReader를 사용했는지 등에 대해서는 '자바로 백준 풀 때의 팁 및 주의점' 글을 참고해주세요. 백준을 자바로 풀어보려고 시작하시는 분이나, 백준에서 자바로 풀 때의 팁을 원하시는 분들도 보시는걸 추천드립니다.

 

 

풀이

  아이디어만 떠오르면 어렵지 않은 문제이다. 말이 있을 때, 격자를 놓을 수 있는 경우의 수를 생각해보자. 사실 이것만 생각나면 끝인 문제이다.

 

1. 첫 번째 말 앞에 1개의 격자를 두는 경우 -> 문제 내에서 1번만 가능

2. 마지막 말 뒤에 1개의 격자를 두는 경우 -> 문제 내에서 1번만 가능

3. 말과 말 사이에 2개의 격자를 두는 경우 -> 말이 k마리라면 k-1번 가능

 

  따라서 위에서 '1'과 '2'는 한번씩만 가능하므로, 칸막이 수 d가 특정 수치까지 남을 때까지는 최대 k-1번 가능한 '3'을 진행해주면 된다. 이 경우 k-1개의 '3'의 경우 중 어떤걸 선택해야 할까? 간격이 큰거부터 계속 골라나가면 된다! '특정 수치'는 몇일까? 3이하로 남기 전까지 진행하면 된다.

long sum = 0;
while (d>3 && !pq.isEmpty()) {
    sum+=pq.poll();
    d-=2;
}

 

  왜 d=3 이하일 경우는 별도로 봐야 할까? 아래의 경우의 수가 있기 때문이다.

- d=1 인 경우 '3'은 진행이 불가하다. '1'과 '2' 중 큰 쪽을 선택해야 한다.

- d=2 인 경우 '1'+'2' 와 '3'을 더 진행하는 것 중 큰 쪽을 선택해야 한다.

- d=3 인 경우 '3'+'1' 과 '3'+'2'와 '1'+'2' 중 큰 쪽을 선택해야 한다.

if (d==1) {
    sum += Math.max(s, e);
} else if (d==3) {
    sum += Math.max(s+e, pq.isEmpty()?0:pq.poll()+(Math.max(s,e)));
} else {
    sum += Math.max(s+e, pq.isEmpty()?0:pq.poll());
}

 

 

코드 : github

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class Main {

    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in), 1<<16);

    public static void main(String[] args) throws Exception {
        new Main().solution();
    }

    private void solution() throws Exception {
        StringTokenizer st = new StringTokenizer(br.readLine());
        int n = Integer.parseInt(st.nextToken());
        int k = Integer.parseInt(st.nextToken());
        int d = Integer.parseInt(st.nextToken());

        st = new StringTokenizer(br.readLine());
        long cur = Integer.parseInt(st.nextToken());
        long s = cur-1;
        if (s < 0) s = 0;

        PriorityQueue<Long> pq = new PriorityQueue<>(Collections.reverseOrder());
        while (--k>0) {
            long tmp = Integer.parseInt(st.nextToken());
            pq.add(tmp-cur-1);
            cur = tmp;
        }

        long e = n-cur;

        long sum = 0;
        while (d>3 && !pq.isEmpty()) {
            sum+=pq.poll();
            d-=2;
        }

        if (d==1) {
            sum += Math.max(s, e);
        } else if (d==3) {
            sum += Math.max(s+e, pq.isEmpty()?0:pq.poll()+(Math.max(s,e)));
        } else {
            sum += Math.max(s+e, pq.isEmpty()?0:pq.poll());
        }

        System.out.println(sum);
    }
}

 

댓글