📖 문제
오늘 동빈이는 여행 가신 부모님을 대신해서 떡집 일을 하기로 했다. 오늘은 떡볶이 떡을 만드는 날이다. 동빈이네 떡볶이 떡은 재밌게도 떡볶이 떡의 길이가 일정하지 않다. 대신에 한 봉지 안에 들어 가는 떡의 총 길이는 절단기로 잘라서 맞춰준다.
절단기에 높이(H)를 지정하면 줄지어진 떡을 한 번에 절단한다. 높이가 H보다 긴 떡은 H 위의 부분이 잘릴 것이고, 낮은 떡은 잘리지 않는다.
예를 들어 높이가 19, 14, 10, 17cm인 떡이 나란히 있고 절단기 높이를 15cm로 지정하면 자른 뒤 떡의 높이는 15, 14, 10, 15cm가 될 것이다. 잘린 떡의 길이는 차례대로 4, 0, 0, 2cm이다. 손님은 6cm 만큼의 길이를 가져간다.
손님이 왔을 때 요청한 총 길이가 M일 때 적어도 M만큼의 떡을 얻기 위해 절단기에 설정할 수 있는 높이의 최댓값을 구하는 프로그램을 작성하시오.
입력 조건
첫째 줄에 떡의 개수 N과 요청한 떡의 길이 M이 주어진다.
(1 <= N <= 1,000,000, 1 <= M <= 2,000,000,000)둘째 줄에는 떡의 개별 높이가 주어진다. 떡 높이의 총합은 항상 M 이상이므로, 손님은 필요한 양만큼 떡을 사갈 수 있다. 높이는 10억보다 작거나 같은 양의 정수 또는 0이다.
출력 조건
적어도 M만큼의 떡을 집에 가져가기 위해 절단기에 설정할 수 있는 높이의 최댓값을 출력한다.
My answer
import sys
from bisect import bisect_left
input=sys.stdin.readline
n,m=map(int,input().split())
dduk=list(map(int,input().split()))
def binary_search(start,end):
if(start>end):
return end
mid=(start+end)//2
tmp=[i-mid for i in dduk if i>mid]
tmp=sum(tmp)
#print(start, end ,mid, tmp)
if(tmp==m):
return mid
elif(tmp<m):
return binary_search(start,mid-1)
else:
return binary_search(mid+1,end)
print(binary_search(0,max(dduk)))
Another answer
# 떡의 개수(N)와 요청한 떡의 길이(M)을 입력
n, m = list(map(int, input().split(' ')))
# 각 떡의 개별 높이 정보를 입력
array = list(map(int, input().split()))
# 이진 탐색을 위한 시작점과 끝점 설정
start = 0
end = max(array)
# 이진 탐색 수행 (반복적)
result = 0
while(start <= end):
total = 0
mid = (start + end) // 2
for x in array:
# 잘랐을 때의 떡볶이 양 계산
if x > mid:
total += x - mid
# 떡볶이 양이 부족한 경우 더 많이 자르기 (오른쪽 부분 탐색)
if total < m:
end = mid - 1
# 떡볶이 양이 충분한 경우 덜 자르기 (왼쪽 부분 탐색)
else:
result = mid # 최대한 덜 잘랐을 때가 정답이므로, 여기에서 result에 기록
start = mid + 1
# 정답 출력
print(result)
풀이
이 문제는 전형적인 이진 탐색 문제로, Parametric search라고 한다. parametrice search란 최적화 문제를 결정문제로 바꿔 해결하는 기법으로, 문제에서 "원하는 조건을 만족하는 가장 알맞은 값을 찾으라"고 할 때 보통 사용한다. 최적화문제를 범위를 좁혀가며 특정 범위를 구하는 것이다.
이번 문제의 아이디어는 높이를 반복해서 조절해가면서 가장 적절한 높이를 찾는 것인데, 절단기의 범위가 1~10어까지의 정수 중 하나이기 때문에 브루트포스처럼 그냥 전부해볼 수는 없다. 따라서 이진탐색을 통해서 시도 횟수를 줄여가는 것이다.
이제 문제 풀이로 들어가보자면 위의 문제의 예시처럼 입력값 n,m이 4,6이고 떡 길이가 19 14 10 17로 주어질 때 맨처음 이진탐색에는 start=0, end=19로 들어가게 된다. 그럼 mid=9가 나오고 절단기 높이가 9일때 남는 떡길이는 19-9=10,14-9=5,10-9=1,17-9=8로 총 24는 m=6보다 크기 때문에 범위를 좁혀 이번엔 start=0, end=8이 들어가게된다. 이런식으로 반복하다보면 이 예시의 경우 딱 6이 되는 경우도 있긴하지만, 6을 찾는문제가 아니기 때문에 종료조건을 start>end가 넘어갈 때 end를 출력하는 것으로 설정해주면 된다. (이 부분이 헷갈렸음 언제 종료해야하는지 여러번 테스트 케이스 시도하며 찾아냄)
(위의 my answer의 함수 첫째 줄에 start, end를 print 해보면서 어떻게 돌아가는지 알 수 있다.)
another answer은 같은 이진탐색을 반복문으로 구현한 것인데, 이러한 파라메트릭 서치같은 문제에서는 재귀를 이용한 이진탐색보다, 반복문을 이용한 이진탐색이 생각하기 쉽다고 한다.
'코딩테스트 > 이것이취업을위한코딩테스트다[Python]' 카테고리의 다른 글
개미 전사-[이것이 취업을 위한 코딩 테스트다] (1) | 2023.09.15 |
---|---|
1로 만들기-[이것이 취업을 위한 코딩 테스트다] (0) | 2023.09.14 |
부품 찾기-[이것이 취업을 위한 코딩 테스트다] (0) | 2023.09.13 |
두 배열의 원소 교체-[이것이 취업을 위한 코딩 테스트다] (0) | 2023.09.05 |
성적이 낮은 순서로 학생 출력하기-[이것이 취업을 위한 코딩 테스트다] (0) | 2023.09.05 |