- [일반화된 접근 방법] 이 문제가 이진 탐색 과제라는 것을 어떻게 알 수 있을까?
- 탐색 목표와 탐색 대상을 정의
- 고려해야 하는 모든 경우의 수를 파악
- 그 다음 각 경우의 수를 선형 탐색 방식으로 접근해 봄
- 선형 탐색의 종료 조건을 파악!
- 각 경우의 수가 가진 규칙성을 파악하며 더 효율적으로 탐색할 수 있는 방법 고민
- 특히, 각 경우의 수가 선형적으로 증가 혹은 감소한다면 이진 탐색으로 접근 가능
- 선형 탐색의 종료 조건을 참고하여 이진 탐색에서 범위를 좁히는 로직을 구성!
접근법을 적용하면 아래와 같음
절단 높이를 수확량으로 변환
선형 관계 파악 과정
중요 포인트 재정리
# 나무 높이 중복을 고려해 Counter 방식으로 나무 높이 정리
counted = {}
for tree in trees:
if tree in counted:
counted[tree] += 1
else:
counted[tree] = 1
# 절단 높이 값을 받아 수확량을 계산하는 함수 구현
def get_amount(h):
total = 0
for tree in counted:
if tree - h > 0:
num = counted[tree]
total += (tree-h) * num
return total
# 최적의 절단 높이를 이진 검색으로 탐색
# h_left: 절단 높이가 0이 되면 수확량이 가장 큰 값이 되므로 수확량 관점에서 최대 기준
# h_right: 절단 높이가 가장 큰 나무의 높이가 되면 수확량은 0이 되므로 수확량 관점에서 최소 기준
# h_answer: 절단 높이를 최대한 높이는 것이 목표이므로 0부터 시작
h_left = 0
h_right = max(counted)
h_answer = 0
while h_left <= h_right:
mid = (h_left + h_right) // 2
amount = get_amount(mid)
# 수확량이 M 이상인 경우, 목표 달성이며 h를 더 높여봄
if amount >= M:
h_left = mid + 1
h_answer = mid
# 수확량이 M 미만인 경우, 목표 미달이며 h를 낮춰야 함
else:
h_right = mid - 1
print(h_answer)
import sys
N, M = list(map(int, sys.stdin.readline().split()))
trees = list(map(int, sys.stdin.readline().split()))
# 나무들을 역순으로 정렬
trees.sort(reverse=True)
# 일관성을 위해 더미 아이템 추가
trees.append(0)
loc = 0
diff = M
while diff > 0:
to_sub = (trees[loc] - trees[loc+1]) * (loc+1)
diff -= to_sub
loc += 1
height = (sum(trees[:loc]) - M) // loc
print(height)