Algorithm

[BOJ] 2805번: 나무 자르기 (매개 변수 탐색)

걸어가는 신사 2022. 1. 26. 23:11

1. 문제

 

2805번: 나무 자르기

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

www.acmicpc.net

(1) 정답의 최대치

  • 정답의 범위: 0 ~ 10억 (Integer type)
  • 잘린 나무의 길이 합 <= 나무 높이의 총합 = 100만 * 10억 (Integer 범위 초과 => long 타입 사용해야 한다.)

 

2. 접근

(1) 키워드 체크하기

  • 적어도 M미터의 나무를 집에 가져가기 위해서 절다기에 설정할 수 있는 높이의 최댓값을 구하는 프로그램을 작성하시오

(2) 매개 변수 만들어 보기

  • 정답을 "매개 변수(Parameter)"로 만들고 Yes/No 문제(결정 문제)로 바꿔 보기

  • 모든 값에 대해서 Yes/No를 채웠다고 생각했을 때, 정렬된 상태인가? Yes
위와 같은 접근으로 매개변수 탐색 알고리즘을 사용해야 한다는 것을 알 수 있다.

매개변수 탐색 알고리즘이 모르고 있다면 아래 링크를 통해 공부해보는 것도 좋을 것 같다.

 

[Algorithm] 매개 변수 탐색 (Parametric Search)

1. 매개 변수 탐색 (Parametric Search) 최적화 문제를 결정 문제로 바꾸어 푸는 것이다. 정답을 파라미터로 만들고 결정문제로 바꾸어 푼다 => 이분 탐색의 아이디어 배열이 0과 1만 존재하며 오름차순

choiyeonho903.tistory.com

 

3. 시간복잡도

  • H를 정해서 결정 문제 한 번 풀기 => O(N)
  • 정답의 범위를 이분 탐색하면서 풀기 => O(logX) 반복
  • 총 시간 복잡도 : O(N logX)

 

4. 구현

  • 이분 탐색 메서드 구현 (가능한 범위에서 H 탐색)
  • 이분 탐색에서 선택된 H가 만족하는지 않는지 결정하는 satisfy 메소드 구현 
public class S3_2805 {
    static int N;
    static int M;
    static int[] tree;
    static int ans;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        String str = br.readLine();
        st = new StringTokenizer(str, " ");
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        tree = new int[N+1];
        str = br.readLine();
        st = new StringTokenizer(str, " ");
        for (int i = 1; i <= N; i++) {
            tree[i] = Integer.parseInt(st.nextToken());
        }
        Arrays.sort(tree);
        binarySearch();
        System.out.println(ans);
    }

    static void binarySearch() {
        int L = 0;
        int R = 1000000000;
        ans = 0;

        while (L<=R) {
           int mid = (L+R)/2;
           if(satisfy(mid)) {
               ans = mid;
               L = mid + 1;
           } else {
               R = mid - 1;
           }
        }
    }

    static boolean satisfy(int h) {
        long sum = 0L;
        for (int i = 1; i <=N; i++) {
            if(tree[i] - h > 0) {
                sum += (tree[i] - h);
            }
        }
        return sum >= M;
    }
}
반응형