I am trying to solve the knapsack problem by applying my own algorithm. I give each item a score (values[i] - weights[i]) and add high score items to my knapsack. But this code replaces each item with the first item of values (5).
def knapsack(weights, values, capacity):
knapsack = []
scores = []
for i in range(len(values)):
score = values[i] - weights[i]
scores.append(score)
weight = 0
while weight < capacity:
if len(scores) != 0:
valuable = max(scores)
knapsack.append(values[scores.index(valuable)])
weight += weights[scores.index(valuable)]
scores.pop(scores.index(valuable))
else:
break
return knapsack
weights = [1, 2, 4, 2, 5]
values = [5, 3, 5, 3, 2]
capacity = 10
print(knapsack(weights, values, capacity))
What is wrong with this code?
Edit: I fixed it but there seems to be a logical error. If:
weights = [8, 2, 6, 7, 9]
values = [3, 11, 13, 7, 4]
capacity = 24
Then there are two items with the same score (8, 3 and 9, 4), but 9, 4 is better since it fits exactly into the knapsack and it has higher value. Even changing line 8 to <= does not help.
You are not removing the appended values from the list as well. Try adding
values.pop(scores.index(valuable))
weights.pop(scores.index(valuable))
to the line before scores.pop(...)
.
Additionally, you need to break out of the loop if the added item would make you over capacity, eg:
if (weight + weights[scores.index(valuable)]) > capacity:
break
You need code to deal with tie-breakers, which reassigns the score index to the highest-valued item which fits under the capacity, eg:
ties = [i for i, x in enumerate(scores) if x == valuable]
if len(ties) > 1:
most_valuable = -1
for idx in ties:
if values[idx] > most_valuable and (weight + weights[idx]) <= capacity:
most_valuable = values[idx]
scores_idx = idx
Full code:
def knapsack(weights, values, capacity):
knapsack = []
scores = []
for i in range(len(values)):
score = values[i] - weights[i]
scores.append(score)
weight = 0
while weight < capacity:
if len(scores) != 0:
valuable = max(scores)
scores_idx = scores.index(valuable)
ties = [i for i, x in enumerate(scores) if x == valuable]
if len(ties) > 1:
most_valuable = -1
for idx in ties:
if values[idx] > most_valuable and (weight + weights[idx]) <= capacity:
most_valuable = values[idx]
scores_idx = idx
if (weight + weights[scores_idx]) > capacity:
break
knapsack.append(values[scores_idx])
weight += weights[scores_idx]
values.pop(scores_idx)
weights.pop(scores_idx)
scores.pop(scores_idx)
else:
break
return knapsack
# weights = [1, 2, 4, 2, 5]
# values = [5, 3, 5, 3, 2]
# capacity = 10
weights = [8, 2, 6, 7, 9]
values = [3, 11, 13, 7, 4]
capacity = 24
print(knapsack(weights, values, capacity))
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.