-
-
Notifications
You must be signed in to change notification settings - Fork 46.6k
Enhancement of the knapsack algorithm with memorization and generalisation #9295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,68 @@ | ||
""" A naive recursive implementation of 0-1 Knapsack Problem | ||
""" A recursive implementation of 0-N Knapsack Problem | ||
https://en.wikipedia.org/wiki/Knapsack_problem | ||
""" | ||
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, | ||
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 | ||
>>> val = [60, 100, 120] | ||
>>> w = [10, 20, 30] | ||
>>> c = len(val) | ||
>>> knapsack(cap, w, val, c) | ||
>>> knapsack(cap, w, val, c, False) | ||
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. | ||
>>> 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) | ||
which is the limit of the capacity. | ||
""" | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You might want to consider a few things before getting into the algorithm:
|
||
# Base Case | ||
if counter == 0 or capacity == 0: | ||
return 0 | ||
|
||
# If weight of the nth item is more than Knapsack of capacity, | ||
# then this item cannot be included in the optimal solution, | ||
# else return the maximum of two cases: | ||
# (1) nth item included | ||
# (2) not included | ||
if weights[counter - 1] > capacity: | ||
return knapsack(capacity, weights, values, counter - 1) | ||
else: | ||
left_capacity = capacity - weights[counter - 1] | ||
new_value_included = values[counter - 1] + knapsack( | ||
left_capacity, weights, values, counter - 1 | ||
) | ||
without_new_value = knapsack(capacity, weights, values, counter - 1) | ||
return max(new_value_included, without_new_value) | ||
@lru_cache | ||
def knapsack_recur(cap: int, c: int) -> int: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
# Base Case | ||
if c == 0 or cap == 0: | ||
return 0 | ||
|
||
# If weight of the nth item is more than Knapsack of capacity, | ||
# then this item cannot be included in the optimal solution, | ||
# else return the maximum of two cases: | ||
# (1) not included | ||
# (2) nth item included one or more times (0-N), if allow_repetition is true | ||
# nth item included only once (0-1), if allow_repetition is false | ||
if weights[c - 1] > cap: | ||
return knapsack_recur(cap, c - 1) | ||
else: | ||
without_new_value = knapsack_recur(cap, c - 1) | ||
if allow_repetition: | ||
new_value_included = values[c - 1] + knapsack_recur( | ||
cap - weights[c - 1], c | ||
) | ||
else: | ||
new_value_included = values[c - 1] + knapsack_recur( | ||
cap - weights[c - 1], c - 1 | ||
) | ||
return max(new_value_included, without_new_value) | ||
|
||
return knapsack_recur(capacity, counter) | ||
|
||
|
||
if __name__ == "__main__": | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The algorithm has been updated to allow repetition. An example/testcase where repetition is used would be appropriate.