[백준 2805] 나무 자르기 (PyPy3)
문제 링크 #
개요 #
- 이분 탐색으로 해결할 수 있는 문제이다.
- Python3을 사용하면 시간초과가 발생하므로 PyPy3를 사용한다.
문제 조건 #
- 일정 높이에 대해 모든 나무를 잘랐을 때, 조건을 만족하는 절단기의 최대 높이(H)를 구하는 문제이다.
- 잘린 나무의 길이의 합은 상근이가 필요로 하는 나무의 길이(M)보다 크거나 같아야 한다.
문제 해설 #
- 나무의 수(N)의 최댓값이 1,000,000이므로 모든 범위에 대해 반복하는 순차 탐색을 이용할 경우 시간초과가 발생한다.
- 시간 복잡도가
O(log n)인 이분 탐색을 이용하면 시간 복잡도가O(n)인 순차 탐색을 쓰는 것보다 훨씬 빠르다. - 이분 탐색은 중간값(
md)을 기준으로 시작하여 조건에 따라
최대/최솟값의 포인터(mx/mn)를 조정하는 탐색 알고리즘이다. - 잘린 나무의 길이의 합(
total)을 구할 때 잘리지 않은 나무에 대한 음수값을 포함하지 않도록 주의한다. - 조건을 만족할 경우 최솟값(
mn)을 중간값(md)보다 크게 맞추며,
반대의 경우 최댓값(mx)을 중간값(md)보다 작게 조정한다. - 이분 탐색을 마치면 최댓값(
mx)에 조건을 만족하는 최대 높이(H)의 값이 남게 된다.
시간 복잡도 #
- 시간 복잡도가
O(log N)인 이분 탐색의 매 반복마다 시간 복잡도가O(n)인for문을 실행하므로
시간 복잡도는O(N log N)이상이 된다. - N의 최댓값 1,000,000에 대해 20,000,000번이 넘는 연산이 실행되므로 Python3으로는 시간 제한 1초를 초과한다.
- PyPy3에 대한 이해가 깊은 편이 아니라 자세한 설명은 어렵지만,
메모리를 더 사용하는 대신 코드를 캐싱하는 PyPy3를 사용하면 시간 제한 안에 해결할 수 있다.
해설 코드 #
python
N, M = map(int, input().split())
trees = list(map(int, input().split()))
mn, md, mx = 0, 0, max(trees)
while mn <= mx:
md = (mx + mn) // 2
total = 0
for tree in trees:
total += tree - md if tree > md else 0
if total >= M:
mn = md + 1
else:
mx = md - 1
print(mx)