본문 바로가기

Algorithm/BaekJoon

[백준] 3020번 - 개똥벌레 (java)

Baekjoon 3020 - 개똥벌레 (클릭 시 이동)

문제

개똥벌레 한 마리가 장애물(석순과 종유석)로 가득찬 동굴에 들어갔다. 동굴의 길이는 N미터이고, 높이는 H미터이다. (N은 짝수) 첫 번째 장애물은 항상 석순이고, 그 다음에는 종유석과 석순이 번갈아가면서 등장한다.

아래 그림은 길이가 14미터이고 높이가 5미터인 동굴이다. (예제 그림)

img

이 개똥벌레는 장애물을 피하지 않는다. 자신이 지나갈 구간을 정한 다음 일직선으로 지나가면서 만나는 모든 장애물을 파괴한다.

위의 그림에서 4번째 구간으로 개똥벌레가 날아간다면 파괴해야하는 장애물의 수는 총 여덟개이다. (4번째 구간은 길이가 3인 석순과 길이가 4인 석순의 중간지점을 말한다)

img

하지만, 첫 번째 구간이나 다섯 번째 구간으로 날아간다면 개똥벌레는 장애물 일곱개만 파괴하면 된다.

동굴의 크기와 높이, 모든 장애물의 크기가 주어진다. 이때, 개똥벌레가 파괴해야하는 장애물의 최솟값과 그러한 구간이 총 몇 개 있는지 구하는 프로그램을 작성하시오.


시간 제한 메모리 제한 제출 정답 맞은 사람 정답 비율
1 초 128 MB 9590 3885 2886 42.058%

입력

첫째 줄에 N과 H가 주어진다. N은 항상 짝수이다. (2 ≤ N ≤ 200,000, 2 ≤ H ≤ 500,000)

다음 N개 줄에는 장애물의 크기가 순서대로 주어진다. 장애물의 크기는 H보다 작은 양수이다.


출력

첫째 줄에 개똥벌레가 파괴해야 하는 장애물의 최솟값과 그러한 구간의 수를 공백으로 구분하여 출력한다.


풀이

  1. 석순과 종유석의 크기별 갯수를 저장할 수 있는 배열을 만든다. int[H+1]

  2. 역순으로 구간합을 구한다.

    만약 H가 5라고 가정했을 때,

    1의 위치에서 개똥벌레가 날아간다면 만나는 석순의 갯수는 크기가 1,2,3,4,5인 석순의 갯수이기 때문이다.

  3. 개똥벌레가 h의 높이에서 날아갈 때 만나는 석순과 종유석의 갯수를 계산하여 저장한다. 이때 최솟값을 함께 구한다.

  4. 최솟값과 같은 값을 count한다.


과정

1. 석순과 종유석의 크기별 갯수를 저장할 수 있는 배열을 만든다. int[H+1]
ceil= new int[H+1];        // 종유석
floor = new int[H+1];    // 석순

for (int i = 0; i < N/2 ; i++) {
    floor[Integer.parseInt(br.readLine())]++;
    ceil[Integer.parseInt(br.readLine())]++;
}

배열을 선언하고 각 값에 해당하는 인덱스에 +1 해준다.


2. 역순으로 구간합을 구한다.
for (int i = H-1; i >0 ; i--) {    //석순과 종유석의 크기는 H보다 작다.
                                // 천장에서 바닥까지 한줄로 이어진 돌(석주)은 없다는 의미.
    ceil[i] += ceil[i+1];
    floor[i] += floor[i+1];
}

3. 개똥벌레가 h의 높이에서 날아갈 때 만나는 석순과 종유석의 갯수를 계산하여 저장한다. 이때 최솟값을 함께 구한다.
int[] stone = new int[H+1];
int min = N+1;

for (int i = 1; i <= H ; i++) {
    stone[i] = floor[i] + ceil[H-i+1];
    min = Math.min(min, stone[i]);
}

마찬가지로 H가 5라고 가정했을 때,

1의 높이에서 날아간다면 floor[1]의 갯수만큼 석순을 만나고 ceil[5]의 갯수만큼 종유석을 만날것이다.

3의 높이에서 날아간다면 floor[3]의 갯수만큼의 석순을, ceil[3]의 갯수만큼의 종유셕을 만날 것이다.


4. 최솟값과 같은 값을 count한다.

최종 소스코드

package BJ_Practice;

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

public class BJ_G5_3020_개똥벌레 {
    static int N,H;
    static int[] ceil,floor;
    static StringTokenizer st;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();

        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        H = Integer.parseInt(st.nextToken());
        ceil= new int[H+1];
        floor = new int[H+1];

        for (int i = 0; i < N/2 ; i++) {
            floor[Integer.parseInt(br.readLine())]++;
            ceil[Integer.parseInt(br.readLine())]++;
        }

        for (int i = H-1; i >0 ; i--) {
            ceil[i] += ceil[i+1];
            floor[i] += floor[i+1];
        }

        int[] stone = new int[H+1];
        int min = N+1;

        for (int i = 1; i <= H ; i++) {
            stone[i] = floor[i] + ceil[H-i+1];
            min = Math.min(min, stone[i]);
        }
        int cnt = 0;
        for (int i = 1; i <= H ; i++) {
            if(stone[i] == min)
                cnt++;
        }
        System.out.println(min + " " + cnt);        
    }
}