[2512] 예산

Young Min Kang·2024년 1월 13일

Baek Joon

목록 보기
18/39
post-thumbnail

문제

출처
국가의 역할 중 하나는 여러 지방의 예산요청을 심사하여 국가의 예산을 분배하는 것이다. 국가예산의 총액은 미리 정해져 있어서 모든 예산요청을 배정해 주기는 어려울 수도 있다. 그래서 정해진 총액 이하에서 가능한 한 최대의 총 예산을 다음과 같은 방법으로 배정한다.

모든 요청이 배정될 수 있는 경우에는 요청한 금액을 그대로 배정한다.
모든 요청이 배정될 수 없는 경우에는 특정한 정수 상한액을 계산하여 그 이상인 예산요청에는 모두 상한액을 배정한다. 상한액 이하의 예산요청에 대해서는 요청한 금액을 그대로 배정한다.
예를 들어, 전체 국가예산이 485이고 4개 지방의 예산요청이 각각 120, 110, 140, 150이라고 하자. 이 경우, 상한액을 127로 잡으면, 위의 요청들에 대해서 각각 120, 110, 127, 127을 배정하고 그 합이 484로 가능한 최대가 된다.

여러 지방의 예산요청과 국가예산의 총액이 주어졌을 때, 위의 조건을 모두 만족하도록 예산을 배정하는 프로그램을 작성하시오.

입력
4
120 110 140 150
485
출력
127

문제 정리

  • 모든 요청이 배정될 수 있는 경우에는 요청한 금액을 그대로 배정
  • 모든 요청이 배정될 수 없는 경우는 특정한 정수 상한액 계산
  • 특정한 정수 상한액 이상의 예산 요청은 모두 상한액을 배정
  • 쓸 수 있는 예산을 정해져있고 각 기준을 정해서 최대의 효율을 뽑아내라
  • 이분탐색으로 접근
  • 특정 예산을 설정 최소 예산금액 ~ 최대 예산 금액 사이로 결정
  • 최소 예산 금액에 대해서는 탐색을 하지 않도록 그냥 1로 설정(문제에서 최소값이 1이라고 정해져있기에)
  • 종료 조건 start <= end

문제 풀이

# 입력
n = int(input()) # 예산을 할당받고자 하는 사람의 수
request_budgets = list(map(int, input().split())) # 예산 요청액들
limit_budget = int(input()) # 총 가용 예산

start = 1 # 시작 예산(최소값 1)
end = max(request_budgets) 
max_budget = 0
while start<=end: # 종료조건 
    base_budget = (start+end) // 2 
    use_budget = 0
    for budget in request_budgets:
        if budget <= base_budget: # 사용하려는 예산이 기준 예산 이하라면
            use_budget += budget # 사용하려는 예산만큼 더해도 됨.
        else: # 예산이 기준예산보다 위라면 기준예산밖에 못 쓴다.
            use_budget += base_budget
    # 또는 예산이 너무 많아서 기준 예산을 쓸데없이 크게 잡은 경우
    if use_budget > limit_budget: # 사용 예산이 리미트 예산 초과라면
        end = base_budget - 1 # 사용할 예산 범위를 줄여야함.
    else: # 사용 예산이 리미트 예산 이하라면
        max_budget = base_budget # 사용한 예산은 무조건 리미트 예산 이하여야하기에 여기서 max값 업데이트
        start = base_budget + 1 # 사용할 예산 범위를 늘려야함.
print(max_budget)

max기준 예산을 어디서 갱신 시킬것인가 범위는 어떻게 잡을 것인가 부등호 처리는 어떻게 할 것인가가 핵심인 문제였다.
처음에는 계속 틀렸었다.
if use_budget > limit_budgetif use_budget >= limit_budget로 작성하고
max_budget = base_budget max값 갱신하는 부분을 예산 이상 부분에 두어서 답이 보다 1 크게 나오는 경우가 빈번했었다.
사용한 예산은 무조건 리미트 예산 이하여야하기에 else문에서 max값 업데이트를 하니 정답으로 처리가 되었다.

문제 후기

보다 제네럴하게 생각을 해야하며 왜 틀렸는지를 면밀하게 살펴봐야한다. 과연 이 부등호가 맞는가 여기서 값을 업데이트하는 것이 맞는가를 생각해야한다. 무작정 if문을 쓰기보다는 기존 조건에서 최대한 답이 되도록 생각해봐야겠다.

    for budget in request_budgets:
        if budget <= base_budget: # 사용하려는 예산이 기준 예산 이하라면
            use_budget += budget # 사용하려는 예산만큼 더해도 됨.
        else: # 예산이 기준예산보다 위라면 기준예산밖에 못 쓴다.
            use_budget += base_budget

이 부분도 좀 더 짧게 쓸 수 있을 듯 하여

    use_budget = sum(min(budget, base_budget) for budget in request_budgets)

이렇게 처리하는 과정을 후에 추가하였다. 요청된 budget이 기준 budget보다 크다면 base_budget로 처리하는 과정이다.

profile
꾸준히 한걸음씩

0개의 댓글