09a

Bounded Knapsack

Bounded knapsack is when we have $n$ items $[(w_i, v_i, n_i)]$ representing weight, value and copies available of each item. This is tribvially reducible to 0/1 knapsack if we simply assume that there are $n_i$ number of distinct items with same weight and value for each of the original item. The time complexity would then be $O(sum(n_i)\times sum(w_i n_i))$.

def knapsack_01(weights: List[int], values: List[int], capacity: int) -> int:
    max_value = [0] * (capacity + 1)

    for weight, value in zip(weights, values):
        for slack in range(capacity, weight - 1, -1):
            max_value[slack] = max(
                max_value[slack], 
                max_value[slack - weight] + value
            )

    return max_value[capacity]

There is a slightly better way to do the reduction. create logaritmic number of copies of items with 1,2,4,.. times weight, value of each item and solve as a 0/1 knapsack problem. Any number of selection of copies of original problem can be represented by a specific selection of new items. Time complexity is $O(sum(w_i) \times n \times \log (\max n_i))$. Ref