문제풀이/백준

백준 나무자르기 문제풀이

soo-dal 2024. 1. 6. 21:36

문제 

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

 

2805번: 나무 자르기

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

www.acmicpc.net

 

 

 

문제 접근 방식

나무 길이 trees 에 대해 절단한 나무 길이 합이 적어도 m 이상을 만족시키는 절단기 높이 height의 최댓값을 구하는 문제이다.

이렇게 최댓값, 최솟값을 구하는 문제를 최적화 문제라고 하는데, 이러한 최적화 문제를 푸는 방법 중 파라메트릭 서치라는 기법이 존재한다.

 

최적화 문제를 True, False를 반환하는 함수를 만들고 이분 탐색으로 수를 넣어보면서 조절해 가며 최적의 답을 구하는 방법이다.

 

이 문제의 경우, 아래 decision(height) 라는 함수를 만들고, 이 함수의 height를 이분법으로 탐색을 한다.

decision(height) = 절단기의 높이 height 이상인 나무들을 모두 잘랐을 때, 잘린 나무 길이의 합이 M 이상인지 여부를 반환한다.

 

decision(height)가 True 라면 해당 높이로 잘라도 만족하는 것이므로 높이을 증가해서 잘라보고,

m 미만이라면 높이를 줄여보는 것이다. 이 늘리고 줄이는 방식을 이분탐색으로 진행한다.

 

시간 복잡도

이분법의 시간 복잡도가 O(k) 이고 decision의 시간복잡도가 O(n) 이다.

k의 최댓값이 1e9이고, n의 최댓값이 1e6 이므로 시간내에 동작할 것이다.

 

코드

MAX=int(1e9)

# decision = 절단기의 높이 height 이상인 나무들을 잘랐을 때, 잘린 나무 길이의 합이 M 이 넘는지 여부를 판단한다.
def decision(height):
    total=0
    for tree in trees:
        if tree>height:
            total+=tree-height

    if total >=m:
        return True

    return False


if __name__=='__main__':
    n,m=map(int,input().split())
    trees=list(map(int,input().split()))

    s,e=0,MAX
    answer=0

    # 이분탐색을 통해 절단기의 높이를 조절한다
    # 특정 절단기 높이가 decision 함수를 만족하면 더 큰 높이를 넣어보고,
    # decision 함수를 만족하지 못하면 작은쪽으로 진행을 한다.
    while s<=e:
        mid =(s+e)//2
        if decision(mid) ==True:
            answer=mid
            s=mid+1
        else:
            e=mid-1

    print(answer)

 

 

회고

파라메트릭 서치의 존재를 기억해놓고 최적화 문제가 나왔을 경우 해당 기법을 선택하여 문제를 풀 수 있도록 하자.