HwangHub
[이분탐색 / python] 백준 2805. 나무 자르기 본문
https://www.acmicpc.net/problem/2805
2805번: 나무 자르기
첫째 줄에 나무의 수 N과 상근이가 집으로 가져가려고 하는 나무의 길이 M이 주어진다. (1 ≤ N ≤ 1,000,000, 1 ≤ M ≤ 2,000,000,000) 둘째 줄에는 나무의 높이가 주어진다. 나무의 높이의 합은 항상 M보
www.acmicpc.net
문제 해석
해당 문제는 "넓은 탐색 범위에서 특정 숫자를 찾는 것"이므로 시간복잡도를 고려했을 때 이분탐색으로 풀어야 한다.
문제 풀이
첫 번째 시도
import sys
input = sys.stdin.readline
"""real input"""
n, m = map(int, input().split())
li = list(map(int, input().split()))
""".text"""
high = max(li)
low = 0
while low <= high:
res = 0
mid = int((high + low)/2)
for i in li:
if (i - mid) >= 0:
res += (i - mid)
else:
res += 0
if res == m:
break
if res > m:
low = mid + 1
elif res < m:
high = mid - 1
print(mid)
이분탐색 로직을 이용하여 가장 높은 토막을 찾아내면 되겠다고 생각했고, 한 지점으로 수렴하면 그 mid 값을 뽑아내면 되겠다고 판단했다. 하지만 출력을 해보니 위 로직으로는 적절한 높이가 구해지지 않았다.
그리고 무엇보다 조건을 만족할 때 최대한 나무를 덜 베어내야 한다는 점을 간과했다.
두 번째 시도
import sys
input = sys.stdin.readline
from random import *
""".input"""
n, m = map(int, input().split())
li = list(map(int, input().split()))
""".text"""
high = max(li)
low = 0
while low <= high:
res = 0
mid = int((high + low)//2)
for i in li:
if (i - mid) >= 0:
res += (i - mid)
else:
res += 0
# if res == m:
# break
if res >= m:
low = mid + 1
else:
high = mid - 1
print(high)
최대한 높은 값을 뽑아내야 하므로,
res == m일 때 바로 멈추는 것이 아니라 while 문의 조건에 따라 탈출하게 설계하고 최대한 잘라내는 높이를 높여야 하므로 하한을 올리는 로직에 등호를 추가한다. 이를 통해 가장 높은 지점에 high와 low가 수렴하게 되고, 마침내 한 지점으로 수렴했을 때 마지막으로 low지점이 high를 넘어서면서 while이 탈출하게 된다. 이 때의 high를 출력하면 정확한 값을 뽑아낼 수 있다.
마지막 지점에서도 답이 맞으면 low는 수렴한 지점에서 +1 된 값이므로 정확하지 않고, 답이 아니면 직전 값이 정답이니 high가 다시 수렴 지점으로 내려가므로 high를 뽑아야 한다. mid의 경우에도 절반으로 나눈 값이므로 마지막 지점에서는 올바른 값을 나타내고 있지 않다.
5 20
4 42 40 26 46
# print("b", high, low, mid, res, m)
# if res >= m:
# low = mid + 1
# else:
# high = mid - 1
# print("a", high, low, mid, res, m)
b 46 0 23 62 20
a 46 24 23 62 20
b 46 24 35 23 20
a 46 36 35 23 20
b 46 36 41 6 20
a 40 36 41 6 20
b 40 36 38 14 20
a 37 36 38 14 20
b 37 36 36 20 20
a 37 37 36 20 20
b 37 37 37 17 20
a 36 37 37 17 20
# print(high)
36
'workspace > 알고리즘' 카테고리의 다른 글
[스택 / python] 백준 17298. 오큰수 (0) | 2023.04.06 |
---|---|
[누적합 / python] 백준 21318. 피아노 체조 (0) | 2023.04.03 |
[이분탐색 / python] 백준 1920. 수 찾기 (0) | 2023.04.01 |
[이분탐색 / python] 13423. Three Dots (0) | 2023.03.31 |
[유클리드 호제법 / python] 백준 2981. 검문 (0) | 2023.03.30 |