@@ -12,7 +12,7 @@ def knapsack(
1212 weights : list [int ],
1313 values : list [int ],
1414 counter : int ,
15- allow_repetition = False ,
15+ allow_repetition : bool = False ,
1616) -> int :
1717 """
1818 Returns the maximum value that can be put in a knapsack of a capacity cap,
@@ -62,6 +62,61 @@ def knapsack_recur(capacity: int, counter: int) -> int:
6262 return knapsack_recur (capacity , counter )
6363
6464
65+ def knapsack_with_count (
66+ capacity : int ,
67+ weights : list [int ],
68+ values : list [int ],
69+ counter : int ,
70+ allow_repetition : bool = False ,
71+ ) -> tuple [int , int ]:
72+ """
73+ Return both the maximum knapsack value and the number of optimal subsets.
74+
75+ The return value is ``(max_value, number_of_optimal_subsets)``.
76+ If multiple choices produce the same maximum value, their counts are added.
77+
78+ >>> cap = 50
79+ >>> val = [60, 100, 120]
80+ >>> w = [10, 20, 30]
81+ >>> c = len(val)
82+ >>> knapsack_with_count(cap, w, val, c)
83+ (220, 1)
84+ >>> knapsack_with_count(cap, w, val, c, True)
85+ (300, 1)
86+ >>> knapsack_with_count(3, [1, 2, 3], [1, 2, 3], 3)
87+ (3, 2)
88+ >>> knapsack_with_count(2, [1, 2], [1, 2], 2, True)
89+ (2, 2)
90+ """
91+
92+ @lru_cache
93+ def knapsack_recur (remaining_capacity : int , item_count : int ) -> tuple [int , int ]:
94+ # Base Case: one empty subset yields value 0.
95+ if item_count == 0 or remaining_capacity == 0 :
96+ return 0 , 1
97+
98+ if weights [item_count - 1 ] > remaining_capacity :
99+ return knapsack_recur (remaining_capacity , item_count - 1 )
100+
101+ left_capacity = remaining_capacity - weights [item_count - 1 ]
102+ included_value , included_count = knapsack_recur (
103+ left_capacity , item_count if allow_repetition else item_count - 1
104+ )
105+ included_value += values [item_count - 1 ]
106+
107+ excluded_value , excluded_count = knapsack_recur (
108+ remaining_capacity , item_count - 1
109+ )
110+
111+ if included_value > excluded_value :
112+ return included_value , included_count
113+ if excluded_value > included_value :
114+ return excluded_value , excluded_count
115+ return included_value , included_count + excluded_count
116+
117+ return knapsack_recur (capacity , counter )
118+
119+
65120if __name__ == "__main__" :
66121 import doctest
67122
0 commit comments