Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

forDevLife

[백준] 2805 - 나무 자르기 본문

알고리즘

[백준] 2805 - 나무 자르기

JH_Lucid 2021. 6. 17. 23:55

아래는 시간초과한 코드다. 매우 큰 수가 입력되어 결국엔 overflow로 인해서 정상적인 값이 나오지 않았고, Long으로 변경하자마자 시간초과 에러가 발생했다. 정석대로 이분 탐색으로 진행해야 한다.

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

public class Main {
    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());
        long M = Long.parseLong(st.nextToken());

        int[] arr = new int[N];
        long max = 0;
        long min = Integer.MAX_VALUE;

        st = new StringTokenizer(br.readLine(), " ");
        for (int i = 0; i < N; i++) {
            arr[i] = Integer.parseInt(st.nextToken());
            max = Math.max(max, arr[i]);
            min = Math.min(min, arr[i]);
        }

        long saw = 0;
        saw = max - M;

        if(saw < 0) {
            saw = 0;
        }
        while(true) {
            long sum = 0;
            for(int i=0; i<N; i++) {
                if(saw < arr[i]) {
                    sum += arr[i] - saw;
                }
            }
            if(sum < M) {
                break;
            }
            saw++;
        }
        System.out.println(saw - 1);
    }
}

 

이분탐색 정석으로 풀었다.

마지막의 start, end를 바꾸는 부분에서 sum == M일 경우에 start를 올리는게 계속 이해가지 않았다.

합이 M(내가 가져가고 싶은 최소 나무의 길이)와 동일할 때, 아직 start와 end 교차가 되지 않았을 수 있다. 이 때 mid 값을 반환하면 일부의 케이스에는 맞지만, 결국 내가 원하는 건 절단기 높이의 최대 값이므로 'end'를 출력하는게 목표이다.

최소 나무 길이를 만족했으므로, end를 줄이게 되면 나무 길이가 더 늘어나기 때문에 다시 줄이는 방향으로 하다보면 정답에 수렴하게 된다.

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

public class Main {
    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());
        long M = Long.parseLong(st.nextToken());

        int[] trees = new int[N];
        st = new StringTokenizer(br.readLine(), " ");

        long max = 0;
        for (int i = 0; i < N; i++) {
            trees[i] = Integer.parseInt(st.nextToken());
            max = Math.max(max, trees[i]);
        }

        long start = 20;
        long end = 40;
        while (start <= end) {
            long mid = (start + end) / 2;
            long sum = 0;
            for (int i = 0; i < N; i++) {
                if (trees[i] > mid) {
                    sum += trees[i] - mid;
                }
            }
            System.out.println("start = " + start);
            System.out.println("mid = " + mid);
            System.out.println("end = " + end);
            System.out.println("sum = " + sum);
            System.out.println();

            if (sum >= M) {
                start = mid + 1;
            } else {
                end = mid - 1;
            }

        }
        System.out.println(end);
    }
}

 

 

조금 다른 문제지만 동일한 컨셉이다.

 

나무가 예상보다 작을경우에는 무조건 end를 줄여 -> mid를 낮춰야 한다.

나무가 예상보다 크거나 같을때에는 가져갈 양의 조건을 만족했으니 -> mid를 최대한 높이는게 목표이다. 

따라서 result를 mid로 우선 갱신한 후, mid를 높이기 위해 start를 낮춰 -> mid를 높게한다.

start가 end를 뛰어넘을 경우 while문을 빠져나가므로, 최종 갱신된 result가 답이된다. 

 

 

'알고리즘' 카테고리의 다른 글

[백준] 1929 - 소수 구하기  (0) 2021.06.18
[백준] 1654 - 랜선 자르기  (0) 2021.06.18
[백준] 18111 - 마인크래프트  (0) 2021.06.17
[백준] 11866 - 요세푸스 문제 0  (0) 2021.06.17
[백준] 2798 - 블랙잭  (0) 2021.06.16
Comments