Skip to content

Commit 4961b3a

Browse files
Jiang15weijiangpre-commit-ci[bot]MaximSmolskiy
authored
Enhancement of the knapsack algorithm with memorization and generalisation (TheAlgorithms#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 <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Maxim Smolskiy <[email protected]>
1 parent 44cf167 commit 4961b3a

File tree

3 files changed

+55
-24
lines changed

3 files changed

+55
-24
lines changed

knapsack/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# A naive recursive implementation of 0-1 Knapsack Problem
1+
# A recursive implementation of 0-N Knapsack Problem
22

33
This overview is taken from:
44

knapsack/knapsack.py

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
1-
"""A naive recursive implementation of 0-1 Knapsack Problem
1+
"""A recursive implementation of 0-N Knapsack Problem
22
https://en.wikipedia.org/wiki/Knapsack_problem
33
"""
44

55
from __future__ import annotations
66

7+
from functools import lru_cache
78

8-
def knapsack(capacity: int, weights: list[int], values: list[int], counter: int) -> int:
9+
10+
def knapsack(
11+
capacity: int,
12+
weights: list[int],
13+
values: list[int],
14+
counter: int,
15+
allow_repetition=False,
16+
) -> int:
917
"""
1018
Returns the maximum value that can be put in a knapsack of a capacity cap,
11-
whereby each weight w has a specific value val.
19+
whereby each weight w has a specific value val
20+
with option to allow repetitive selection of items
1221
1322
>>> cap = 50
1423
>>> val = [60, 100, 120]
@@ -17,28 +26,40 @@ def knapsack(capacity: int, weights: list[int], values: list[int], counter: int)
1726
>>> knapsack(cap, w, val, c)
1827
220
1928
20-
The result is 220 cause the values of 100 and 120 got the weight of 50
29+
Given the repetition is NOT allowed,
30+
the result is 220 cause the values of 100 and 120 got the weight of 50
2131
which is the limit of the capacity.
32+
>>> knapsack(cap, w, val, c, True)
33+
300
34+
35+
Given the repetition is allowed,
36+
the result is 300 cause the values of 60*5 (pick 5 times)
37+
got the weight of 10*5 which is the limit of the capacity.
2238
"""
2339

24-
# Base Case
25-
if counter == 0 or capacity == 0:
26-
return 0
27-
28-
# If weight of the nth item is more than Knapsack of capacity,
29-
# then this item cannot be included in the optimal solution,
30-
# else return the maximum of two cases:
31-
# (1) nth item included
32-
# (2) not included
33-
if weights[counter - 1] > capacity:
34-
return knapsack(capacity, weights, values, counter - 1)
35-
else:
36-
left_capacity = capacity - weights[counter - 1]
37-
new_value_included = values[counter - 1] + knapsack(
38-
left_capacity, weights, values, counter - 1
39-
)
40-
without_new_value = knapsack(capacity, weights, values, counter - 1)
41-
return max(new_value_included, without_new_value)
40+
@lru_cache
41+
def knapsack_recur(capacity: int, counter: int) -> int:
42+
# Base Case
43+
if counter == 0 or capacity == 0:
44+
return 0
45+
46+
# If weight of the nth item is more than Knapsack of capacity,
47+
# then this item cannot be included in the optimal solution,
48+
# else return the maximum of two cases:
49+
# (1) nth item included only once (0-1), if allow_repetition is False
50+
# nth item included one or more times (0-N), if allow_repetition is True
51+
# (2) not included
52+
if weights[counter - 1] > capacity:
53+
return knapsack_recur(capacity, counter - 1)
54+
else:
55+
left_capacity = capacity - weights[counter - 1]
56+
new_value_included = values[counter - 1] + knapsack_recur(
57+
left_capacity, counter - 1 if not allow_repetition else counter
58+
)
59+
without_new_value = knapsack_recur(capacity, counter - 1)
60+
return max(new_value_included, without_new_value)
61+
62+
return knapsack_recur(capacity, counter)
4263

4364

4465
if __name__ == "__main__":

knapsack/tests/test_knapsack.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def test_base_case(self):
3030

3131
def test_easy_case(self):
3232
"""
33-
test for the base case
33+
test for the easy case
3434
"""
3535
cap = 3
3636
val = [1, 2, 3]
@@ -48,6 +48,16 @@ def test_knapsack(self):
4848
c = len(val)
4949
assert k.knapsack(cap, w, val, c) == 220
5050

51+
def test_knapsack_repetition(self):
52+
"""
53+
test for the knapsack repetition
54+
"""
55+
cap = 50
56+
val = [60, 100, 120]
57+
w = [10, 20, 30]
58+
c = len(val)
59+
assert k.knapsack(cap, w, val, c, True) == 300
60+
5161

5262
if __name__ == "__main__":
5363
unittest.main()

0 commit comments

Comments
 (0)