ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 37. 예산 문제
    Python/파이썬 자료구조 알고리듬 2019. 7. 1. 15:29
    반응형

    부서별로 필요한 물품 하나씩을 신청받았습니다.

    정해진 예산을 초과하는 경우 '모든 부서'의 물품을 구매해 줄 수는 없습니다. 

    최대한 '많은 부서'의 물품을 구매하려고 합니다.

     

    물품은 조각나지 않으며, 물품의 일부만 구매할 수 없습니다.

    그래서 물품을 구매해 줄 때는 각 부서가 신청한 금액이 정확히 사용됩니다. 

    예를 들어 10원짜리 물품을 신청한 부서에는 정확히 10원짜리 물품이 지원되어야 하며, 10원보다 적은 금액의 물품을 대신 구매해 줄 수는 없습니다.

    재귀로 풀어보았습니다. (삽질의 시작)

    def allocate_base():
        sum = 0  # 요청의 합
        index = len(request)
        count = 0  # 예산에 반영된 부서의 수
        return allocate(index, count, sum)
    
    
    def allocate(index, count, sum):
        print(index, count, sum)
        if sum > budget:
            return count - 1
        elif index == 0:
            return count
        else:
            return max(allocate(index-1, count+1, sum+request[index-1]),
                       allocate(index-1, count, sum))
    
    
    request = [1, 2, 3, 4, 5]  # 각 부서별 요청
    budget = 7  # 총 예산
    print(allocate_base())  # 4

    생각의 흐름을 따라 코딩을 한 거라 좀 난잡한 느낌이 들더군요. ㅎㅎ

    그래서 다시 보니 count 변수를 안 쓰고 코딩할 수 있다는 것을 알았습니다.

    def allocate(index, sum):
        print(index, sum)
        if sum > budget:
            return -1
        elif index == 0:
            return 0
        else:
            return max(1 + allocate(index-1, sum+request[index-1]),
                       allocate(index-1, sum))
    
    
    request = [1, 2, 2, 4, 5]  # 각 부서별 요청
    budget = 5  # 총 예산
    sum = 0  # 요청의 합
    index = len(request)
    print(allocate(index, sum))

    count 변수가 없으니 깔끔해졌습니다. 

    그런데 이걸 어떻게 배열을 이용한 DP(동적 계획법)로 바꿔볼까 고민하다가,
    탐욕법으로 풀린다는 걸 알아버렸습니다. ㅠ,.ㅠ

    나눌 수 없는 물건이라는 단어에 혹해서 탐욕법으론 안 되겠거니 한 겁니다.

    def allocate(request, budget):
        request.sort()
        length = 0
        for i in range(len(request)):
            budget -= request[i]
            if budget >= 0:
                i += 1
                length += 1
            else:
                break
        return length
    
    
    print(allocate([1,2,3,4,5], 10))
    

     

    지워버리긴 아까워서, 동적 계획법으로 작성한 것을 같이 올립니다. 

    뒷정리도 안한 코드 입니다. 답은 제대로 나오는 것 같네요..

    동적 계획법은 배열을 어떻게 짜느냐가 풀이의 핵심인 것 같습니다. 

    배낭 문제보다 배열이 더 복잡해졌네요. 

    def show(array):
        for i, v in enumerate(array):
            print('b', i, v)
    
    
    def allocate(request, budget):
        array = [[[0, budget] for _ in range(len(request)+1)] for _ in range(budget+1)]
        # array[b][r][0] = 예산이 b일 때, r번째 부서일 때, 지급 가능한 총 신청 부서수
        # array[b][r][1] = 예산이 b일 때, r번째 부서일 때, 남은 예산
        for b in range(1, budget + 1):
            for r in range(1, len(request) + 1):
                if request[r-1] > b:  # 남은 예산보다 요청이 큰 경우
                    array[b][r] = array[b][r-1]  # 남은 예산은 그대로, 요청 무시
                else:  # 남은 예산보다 요청이 작거나 같은 경우
                    if array[b-request[r-1]][r-1][0] + 1 > array[b][r-1][0]:
                        # 요청을 반영했을 때 부서수가, 하지 않았을 때 보다 클 때만, 요청을 반영한다.
                        array[b][r] = [array[b-request[r-1]][r-1][0] + 1,
                                   array[b-request[r-1]][r-1][1]-request[r-1]]
                        # 지급 가능한 부서 수는 [이전 지급 가능 부서 수] 보다 [1] 증가
                        # 예산은 [이전 예산] 보다 [신청] 만큼 감소
                    else:
                        array[b][r] = array[b][r-1]
    
        show(array)
        return array[budget][len(request)][0]
    
    
    print(allocate([4, 3, 3, 1, 1], 4))  # 각 부서별 요청, 총 예산
    print(allocate([1, 1, 3, 3, 4], 4))  # 각 부서별 요청, 총 예산
    b 0 [[0, 4], [0, 4], [0, 4], [0, 4], [0, 4], [0, 4]]
    b 1 [[0, 4], [0, 4], [0, 4], [0, 4], [1, 3], [1, 3]]
    b 2 [[0, 4], [0, 4], [0, 4], [0, 4], [1, 3], [2, 2]]
    b 3 [[0, 4], [0, 4], [1, 1], [1, 1], [1, 1], [2, 2]]
    b 4 [[0, 4], [1, 0], [1, 0], [1, 0], [2, 0], [2, 0]]
    2
    b 0 [[0, 4], [0, 4], [0, 4], [0, 4], [0, 4], [0, 4]]
    b 1 [[0, 4], [1, 3], [1, 3], [1, 3], [1, 3], [1, 3]]
    b 2 [[0, 4], [1, 3], [2, 2], [2, 2], [2, 2], [2, 2]]
    b 3 [[0, 4], [1, 3], [2, 2], [2, 2], [2, 2], [2, 2]]
    b 4 [[0, 4], [1, 3], [2, 2], [2, 2], [2, 2], [2, 2]]
    2
    반응형
Designed by Tistory.