Algorithm/BOJ

[백준 - 2805] 나무 자르기 - Java

ikjo 2022. 4. 15. 02:25

문제 설명

 

 

2805번: 나무 자르기

첫째 줄에 나무의 수 N과 상근이가 집으로 가져가려고 하는 나무의 길이 M이 주어진다. (1 ≤ N ≤ 1,000,000, 1 ≤ M ≤ 2,000,000,000) 둘째 줄에는 나무의 높이가 주어진다. 나무의 높이의 합은 항상 M보

www.acmicpc.net

 

풀이 회고

해당 문제는 이분 탐색을 이용하여 해결할 수 있었습니다. 우선 문제에서 요구하는 것은 최소 m 만큼의 나무 높이를 얻기 위해 n개의 나무를 자를 절단기의 최대 높이를 구하는 것입니다.

 

우선 이분 탐색을 위해 다음과 같이 n개의 나무의 높이를 배열 각각의 요소에 할당한 후 오름차순으로 정렬합니다.

 

        for (int i = 0; i < n; i++) {
            trees[i] = Integer.parseInt(st.nextToken());
        }

        Arrays.sort(trees);

 

이후 문제에서 요구하는 절단기의 높이를 구하기 위해 이분 탐색을 위한 시작점을 0으로, 끝점을 나무의 최대 높이로 지정합니다. 이때 절단기의 높이가 0이라는 것은 모든 나무를 다 베어 각각의 나무 높이 합 만큼의 나무 높이(sumOfCutTrees)를 얻을 수 있음을 의미하며, 절단기의 높이가 나무의 최대 높이라는 것은 모든 나무를 다 베지 못하여 0만큼의 나무 높이(sumOfCutTrees)만을 얻을 수 있음을 의미합니다.  이때 주의해야 할 점은 각각의 나무 높이가 최대 10억까지 될 수 있는데다가 나무의 개수가 최대 1백만개가 될 수 있으므로 sumOfCutTrees의 타입은 넉넉하게 long 타입으로 선언해주어야 합니다.

 

        long sumOfCutTrees;
        int start = 0, end = trees[n - 1], heightOfSaw;
        int result = 0;

        while (start <= end) {
            ...
        }

 

절단기의 높이를 시작점과 끝점을 기준으로 중간점으로 설정해가면서(이분 탐색을 하면서) 각각의 나무들을 베어가면서 얻을 수 있는 나무 높이를 구합니다. 이를 위해 별도 메서드 로직을 다음과 같이 구현해주었습니다.

 

    public static long getSumOfCutTrees(int heightOfSaw) {
        long sum = 0;

        for (int i = 0; i < n; i++) {
            if (trees[i] > heightOfSaw) {
                sum += trees[i] - heightOfSaw;
            }
        }

        return sum;
    }

 

이후 모든 나무를 베어 얻은 나무 높이가 목표로 하는 m 보다 작으면 끝점을 낮추어(절단기의 높이를 낮추어) 다음 탐색 시에는 더 많은 나무를 얻도록 하고 m 보다 크다면 시작점을 높여(절단기의 높이를 늘려) 다음 탐색 시에는 더 적은 나무를 얻도록 하여 문제에서 요구하는 값에 근접해지도록 합니다. 이때 모든 나무를 베어 얻은 나무 높이가 m 보다 같다면 이는 해당 절단기의 높이가 문제에서 요구하는 것처럼 최대의 높이를 가지기 때문에 더이상의 탐색이 필요 없이 while 문에서 break를 시킵니다.

 

        long sumOfCutTrees;
        int start = 0, end = trees[n - 1], heightOfSaw;
        int result = 0;

        while (start <= end) {
            heightOfSaw = (start + end) / 2;
            sumOfCutTrees = getSumOfCutTrees(heightOfSaw);

            if (sumOfCutTrees < m) {
                end = heightOfSaw - 1;
            }
            else if (sumOfCutTrees > m) {
                result = Math.max(heightOfSaw, result);
                start = heightOfSaw + 1;
            }
            else {
                result = heightOfSaw;
                break;
            }
        }

        System.out.println(result);

 

전체 소스 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

class Main {

    static int[] trees;
    static int n, m;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());
        trees = new int[n];
        st = new StringTokenizer(br.readLine());

        for (int i = 0; i < n; i++) {
            trees[i] = Integer.parseInt(st.nextToken());
        }

        Arrays.sort(trees);

        long sumOfCutTrees;
        int start = 0, end = trees[n - 1], heightOfSaw;
        int result = 0;

        while (start <= end) {
            heightOfSaw = (start + end) / 2;
            sumOfCutTrees = getSumOfCutTrees(heightOfSaw);

            if (sumOfCutTrees < m) {
                end = heightOfSaw - 1;
            }
            else if (sumOfCutTrees > m) {
                result = Math.max(heightOfSaw, result);
                start = heightOfSaw + 1;
            }
            else {
                result = heightOfSaw;
                break;
            }
        }

        System.out.println(result);
    }

    public static long getSumOfCutTrees(int heightOfSaw) {
        long sum = 0;

        for (int i = 0; i < n; i++) {
            if (trees[i] > heightOfSaw) {
                sum += trees[i] - heightOfSaw;
            }
        }

        return sum;
    }
}

 

 

참고자료

  • https://www.acmicpc.net/problem/2805

 

 

'Algorithm > BOJ' 카테고리의 다른 글

[백준 - 7569] 토마토 - Java  (0) 2022.05.04
[백준 - 11047] 동전 0 - Java  (0) 2022.04.18
[백준 - 6603] 로또 - Java  (0) 2022.04.02
[백준 - 1043] 거짓말 - Java  (0) 2022.03.30
[백준 - 18111] 마인크래프트 - Java  (0) 2022.03.26