코딩테스트/백준

[백준 2805] 나무 자르기 (S2)

34suuuuu 2025. 4. 21. 23:43

 

📍 문제 

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

 

📍 문제 풀이

이분탐색을 이용하는 문제다. 

이분탐색에서 가장 중요한 점은 내가 구해야하는 값이 무엇인지를 정확히 알고있는 것이다.

이 경우는 절단기에 설정할 수 있는 높이의 최대값이다.

 

그렇다면 이 값들을 아래와 같이 초기화해줄 수 있다.

절단기에 설정할 수 있는 높이 start의 최소값은 0

절단기에 설정할 수 있는 높이의 최대값 end는 나무들의 높이 중 최대값

 

배열의 원소들을 순회하면서 해당 나무들에서 높이 mid를 빼주어 합을 구해야한다.

 

이때 설정한 높이 mid가 실제 나무의 높이보다 클 수 있기 때문에 이 경우에는 가져갈 수 있는 나무가 0이다. 반대의 경우에는 배열의 값 - mid 값이기 때문에 두 값 중 더 큰 값을 구해서 더해줘야한다.

그리고 나무 한 그루의 최대 길이가 1,000,000,000 (10억)이기 때문에 합산을 나타내는 sum변수의 자료형은 int 타입이 아닌 long 타입으로 지정해줘야한다. 

 

이렇게 구한 sum과 m값을 비교해 sum < m 이라면 상근이가 가져갈 나무가 너무 작은 경우이기 때문에 절단기의 설정 높이를 낮춰야한다. 반대의 경우는 높여야한다. 

 

📍 전체 코드

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

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

		int n = Integer.parseInt(st.nextToken());
		int m = Integer.parseInt(st.nextToken());

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

		int start = 0;
		int end = Arrays.stream(trees).max().getAsInt(); // 나무 높이의 최대값

		while (start < end) {
			int mid = (start + end) / 2;

			long sum = 0;	// 상근이가 가져갈 수 있는 나무의 합
			for (int tree : trees) {
				// 절단기 설정 높이가 나무의 높이보다 큰 경우 : 0
				// 작거나 같은 경우 : tree - mid
				sum += Math.max(tree - mid, 0);
			}

			if (sum < m) {    // 너무 조금 자른 경우 -> 높이는 내려야함
				end = mid;
			} else {	// 너무 많이 자른 경우 -> 높이를 올려야함
				start = mid + 1;
			}
		}
		System.out.println(start  - 1);

	}
}