Knapsack problem/Unbounded: Difference between revisions

Line 566:
===General Dynamic Programming solution===
 
A dynamic programming approach using a 2-dimensional table (One dimension for weight and one for volume). Because this approach requires that all weights and volumes be integer, I multiplied the weights and volumes by enough to make them integer. This algorithm takes O(wvw*v) space and O(wvnw*v*n) time, where w = weight of sack, v = volume of sack, n = number of types of items. To solve this specific problem it's much slower than the brute force solution.
 
<python>
<python>from collections import namedtuple
from itertools import product, izip
<python>from collections import namedtuple
 
Bounty = namedtuple('Bounty', 'name value weight volume')
 
# "namedtuple" is only available in Python 2.6+; for earlier versions use this instead:
# class Bounty:
Line 579 ⟶ 582:
# self.volume = volume
 
itemssack = [ Bounty('panaceasack', 3000, 3 0, 250, 25250),
Bounty('ichor', 1800, 2, 15),
Bounty('gold', 2500, 20, 2),
]
sack = Bounty('sack', 0, 250, 250)
 
items = [Bounty('panacea', 3000, 3, 25),
def totvalue(itemscount, items=items, sack=sack):
Bounty('ichor', 1800, 2, 15),
"""\
Bounty('gold', 2500, 20, 2),]
 
 
def tot_value(items_count):
"""\
Given the count of each item in the sack return -1 if they can't be carried or their total value.
 
(also return the negative of the weight and the volume so taking the max of a series of return
values will minimise the weight if values tie, and minimise the volume if values and weights tie).
"""
global items, sack
weight = sum( n*item.weight for n, item in zip(itemscount, items) )
volumeweight = sum( n * item.volumeweight for n, item in zipizip(itemscountitems_count, items) )
weightvolume = sum( n * item.weightvolume for n, item in zipizip(itemscountitems_count, items) )
if weight ><= sack.weight orand volume ><= sack.volume:
return sum( n * item.value for n, item in zipizip(itemscountitems_count, items) ), -weight, -volume
else:
return -1, 0, 0
return sum( n*item.value for n, item in zip(itemscount, items) ), -weight, -volume
 
 
def knapsack_dp(items = items, sack = sack):
"""
Solves the Knapsack problem, with two sets of weights,
using a dynamic programming approach
"""
global items, sack
 
# (weight+1) x (volume+1) table
Line 608 ⟶ 616:
# with a sack of weight w and volume v.
# They all start out as 0 (empty sack)
table = [ [0] * (sack.volume + 1) for i in rangexrange(sack.weight + 1) ]
 
for w in rangexrange(0, sack.weight + 1):
for v in rangexrange(0, sack.volume + 1):
# Consider the optimal solution, and consider the "last item" added
# to the sack. Removing this item must produce an optimal solution
Line 619 ⟶ 627:
# Only consider items that would fit:
if w >= item.weight and v >= item.volume:
table[w][v] = \max(table[w][v],
max(table[w][v], # Optimal solution to subproblem + value of item:
# Optimal solution to subproblem + value of table[w - item:.weight][v - item.volume] + item.value)
 
table[w-item.weight][v-item.volume] + item.value)
# Backtrack through matrix to re-construct optimum:
result = [0] * len(items)
w = sack.weight; v = sack.volume
while table[w][v] != 0:sack.volume
while table[w][v]:
# Find the last item that was added:
i = [table[w-item.weight][v-item.volume] + item.value for item in items].index(table[w][v])
 
for item in items].index(table[w][v])
# Record it in the result, and remove it:
result[i] += 1
Line 638 ⟶ 646:
return result
 
maxitems = knapsack_dp()
maxvalue, maxweight, maxvolume = totvalue(maxitems)
maxweight = -maxweight; maxvolume = -maxvolume
 
maxitemsmax_items = knapsack_dp()
print "The maximum value achievable (by dynamic programming) is %g" % maxvalue
max_value, max_weight, max_volume = tot_value(max_items)
print " The number of %s items to achieve this is: %s, respectively" % (
max_weight = -max_weight
','.join(item.name for item in items), maxitems )
max_volume = -max_volume
print " The weight to carry is %d, and the volume used is %d" % (
 
maxweight, maxvolume )</python>
print "The maximum value achievable (by dynamicexhaustive programmingsearch) is %g." % maxvaluemax_value
item_names = ", ','".join(item.name for item in items), maxitems )
print " The number of %s items to achieve this is: %s, respectively." % (item_names, max_items)
print " The weight to carry is %d.3g, and the volume used is %d.3g." % (max_weight, max_volume)
</python>
 
Sample output
Anonymous user