Enhancement of the knapsack algorithm with memorization and generalisation (#9295)

* enhance knapsack problem

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* wei/refactor code

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Update test_knapsack.py

* Update knapsack.py

* Update test_knapsack.py

* Update knapsack.py

* Update knapsack.py

* Update knapsack.py

* Update knapsack.py

* Update knapsack.py

* Update test_knapsack.py

---------

Co-authored-by: weijiang <weijiang@weijiangs-MacBook-Pro.local>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Maxim Smolskiy <mithridatus@mail.ru>
This commit is contained in:
Wei Jiang
2025-08-27 00:10:22 +02:00
committed by GitHub
parent 44cf167175
commit 4961b3aa89
3 changed files with 54 additions and 23 deletions

View File

@@ -1,4 +1,4 @@
# A naive recursive implementation of 0-1 Knapsack Problem # A recursive implementation of 0-N Knapsack Problem
This overview is taken from: This overview is taken from:

View File

@@ -1,14 +1,23 @@
"""A naive recursive implementation of 0-1 Knapsack Problem """A recursive implementation of 0-N Knapsack Problem
https://en.wikipedia.org/wiki/Knapsack_problem https://en.wikipedia.org/wiki/Knapsack_problem
""" """
from __future__ import annotations from __future__ import annotations
from functools import lru_cache
def knapsack(capacity: int, weights: list[int], values: list[int], counter: int) -> int:
def knapsack(
capacity: int,
weights: list[int],
values: list[int],
counter: int,
allow_repetition=False,
) -> int:
""" """
Returns the maximum value that can be put in a knapsack of a capacity cap, Returns the maximum value that can be put in a knapsack of a capacity cap,
whereby each weight w has a specific value val. whereby each weight w has a specific value val
with option to allow repetitive selection of items
>>> cap = 50 >>> cap = 50
>>> val = [60, 100, 120] >>> val = [60, 100, 120]
@@ -17,28 +26,40 @@ def knapsack(capacity: int, weights: list[int], values: list[int], counter: int)
>>> knapsack(cap, w, val, c) >>> knapsack(cap, w, val, c)
220 220
The result is 220 cause the values of 100 and 120 got the weight of 50 Given the repetition is NOT allowed,
the result is 220 cause the values of 100 and 120 got the weight of 50
which is the limit of the capacity. which is the limit of the capacity.
>>> knapsack(cap, w, val, c, True)
300
Given the repetition is allowed,
the result is 300 cause the values of 60*5 (pick 5 times)
got the weight of 10*5 which is the limit of the capacity.
""" """
# Base Case @lru_cache
if counter == 0 or capacity == 0: def knapsack_recur(capacity: int, counter: int) -> int:
return 0 # Base Case
if counter == 0 or capacity == 0:
return 0
# If weight of the nth item is more than Knapsack of capacity, # If weight of the nth item is more than Knapsack of capacity,
# then this item cannot be included in the optimal solution, # then this item cannot be included in the optimal solution,
# else return the maximum of two cases: # else return the maximum of two cases:
# (1) nth item included # (1) nth item included only once (0-1), if allow_repetition is False
# (2) not included # nth item included one or more times (0-N), if allow_repetition is True
if weights[counter - 1] > capacity: # (2) not included
return knapsack(capacity, weights, values, counter - 1) if weights[counter - 1] > capacity:
else: return knapsack_recur(capacity, counter - 1)
left_capacity = capacity - weights[counter - 1] else:
new_value_included = values[counter - 1] + knapsack( left_capacity = capacity - weights[counter - 1]
left_capacity, weights, values, counter - 1 new_value_included = values[counter - 1] + knapsack_recur(
) left_capacity, counter - 1 if not allow_repetition else counter
without_new_value = knapsack(capacity, weights, values, counter - 1) )
return max(new_value_included, without_new_value) without_new_value = knapsack_recur(capacity, counter - 1)
return max(new_value_included, without_new_value)
return knapsack_recur(capacity, counter)
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -30,7 +30,7 @@ class Test(unittest.TestCase):
def test_easy_case(self): def test_easy_case(self):
""" """
test for the base case test for the easy case
""" """
cap = 3 cap = 3
val = [1, 2, 3] val = [1, 2, 3]
@@ -48,6 +48,16 @@ class Test(unittest.TestCase):
c = len(val) c = len(val)
assert k.knapsack(cap, w, val, c) == 220 assert k.knapsack(cap, w, val, c) == 220
def test_knapsack_repetition(self):
"""
test for the knapsack repetition
"""
cap = 50
val = [60, 100, 120]
w = [10, 20, 30]
c = len(val)
assert k.knapsack(cap, w, val, c, True) == 300
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()