from collections import namedtuple
Item = namedtuple('Item', 'weight cost')
def knapsack_costs(items, weight_limit):
current_col = [0] * (weight_limit + 1)
for i in xrange(1, len(items) + 1):
item = items[i - 1]
for w in xrange(weight_limit, 0, -1):
current_col[w] = max(current_col[w], current_col[w - 1])
if w >= item.weight:
current_col[w] = max(
current_col[w],
current_col[w - item.weight] + item.cost
)
return current_col
def knapsack(items, weight_limit):
if not items or not weight_limit:
return []
if len(items) == 1:
return [items[0]] if items[0].weight <= weight_limit else []
m = len(items) / 2
items_left = items[:m]
items_right = items[m:]
costs_left = knapsack_costs(items_left, weight_limit)
costs_right = knapsack_costs(items_right, weight_limit)
best_i = 0
best_cost = 0
for i in xrange(weight_limit + 1):
cur_cost = costs_left[i] + costs_right[-1 - i]
if cur_cost > best_cost:
best_i = i
best_cost = cur_cost
return knapsack(items_left, best_i) + knapsack(items_right, weight_limit - best_i)
print knapsack([Item(1,100), Item(2, 200), Item(5, 3000)], 7)
CmZyb20gY29sbGVjdGlvbnMgaW1wb3J0IG5hbWVkdHVwbGUKSXRlbSA9IG5hbWVkdHVwbGUoJ0l0ZW0nLCAnd2VpZ2h0IGNvc3QnKQoKZGVmIGtuYXBzYWNrX2Nvc3RzKGl0ZW1zLCB3ZWlnaHRfbGltaXQpOgoJY3VycmVudF9jb2wgPSBbMF0gKiAod2VpZ2h0X2xpbWl0ICsgMSkKCWZvciBpIGluIHhyYW5nZSgxLCBsZW4oaXRlbXMpICsgMSk6CgkJaXRlbSA9IGl0ZW1zW2kgLSAxXQoJCWZvciB3IGluIHhyYW5nZSh3ZWlnaHRfbGltaXQsIDAsIC0xKToKCQkJY3VycmVudF9jb2xbd10gPSBtYXgoY3VycmVudF9jb2xbd10sIGN1cnJlbnRfY29sW3cgLSAxXSkKCQkJaWYgdyA+PSBpdGVtLndlaWdodDoKCQkJCWN1cnJlbnRfY29sW3ddID0gbWF4KAoJCQkJCWN1cnJlbnRfY29sW3ddLAoJCQkJCWN1cnJlbnRfY29sW3cgLSBpdGVtLndlaWdodF0gKyBpdGVtLmNvc3QKCQkJCSkKCXJldHVybiBjdXJyZW50X2NvbAoKZGVmIGtuYXBzYWNrKGl0ZW1zLCB3ZWlnaHRfbGltaXQpOgoJaWYgbm90IGl0ZW1zIG9yIG5vdCB3ZWlnaHRfbGltaXQ6CgkJcmV0dXJuIFtdCglpZiBsZW4oaXRlbXMpID09IDE6CgkJcmV0dXJuIFtpdGVtc1swXV0gaWYgaXRlbXNbMF0ud2VpZ2h0IDw9IHdlaWdodF9saW1pdCBlbHNlIFtdCgltID0gbGVuKGl0ZW1zKSAvIDIKCWl0ZW1zX2xlZnQgPSBpdGVtc1s6bV0KCWl0ZW1zX3JpZ2h0ID0gaXRlbXNbbTpdCgljb3N0c19sZWZ0ID0ga25hcHNhY2tfY29zdHMoaXRlbXNfbGVmdCwgd2VpZ2h0X2xpbWl0KQoJY29zdHNfcmlnaHQgPSBrbmFwc2Fja19jb3N0cyhpdGVtc19yaWdodCwgd2VpZ2h0X2xpbWl0KQoJYmVzdF9pID0gMAoJYmVzdF9jb3N0ID0gMAoJZm9yIGkgaW4geHJhbmdlKHdlaWdodF9saW1pdCArIDEpOgoJCWN1cl9jb3N0ID0gY29zdHNfbGVmdFtpXSArIGNvc3RzX3JpZ2h0Wy0xIC0gaV0KCQlpZiBjdXJfY29zdCA+IGJlc3RfY29zdDoKCQkJYmVzdF9pID0gaQoJCQliZXN0X2Nvc3QgPSBjdXJfY29zdAoJcmV0dXJuIGtuYXBzYWNrKGl0ZW1zX2xlZnQsIGJlc3RfaSkgKyBrbmFwc2FjayhpdGVtc19yaWdodCwgd2VpZ2h0X2xpbWl0IC0gYmVzdF9pKQoKCnByaW50IGtuYXBzYWNrKFtJdGVtKDEsMTAwKSwgSXRlbSgyLCAyMDApLCBJdGVtKDUsIDMwMDApXSwgNyk=