1
- """A naive recursive implementation of 0-1 Knapsack Problem
1
+ """A recursive implementation of 0-N Knapsack Problem
2
2
https://en.wikipedia.org/wiki/Knapsack_problem
3
3
"""
4
4
5
5
from __future__ import annotations
6
6
7
+ from functools import lru_cache
7
8
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 :
9
17
"""
10
18
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
12
21
13
22
>>> cap = 50
14
23
>>> val = [60, 100, 120]
@@ -17,28 +26,40 @@ def knapsack(capacity: int, weights: list[int], values: list[int], counter: int)
17
26
>>> knapsack(cap, w, val, c)
18
27
220
19
28
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
21
31
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.
22
38
"""
23
39
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 )
42
63
43
64
44
65
if __name__ == "__main__" :
0 commit comments