from itertools import product, izip
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:
# def __init__(self, name, value, weight, volume):
# self.name = name
# self.value = value
# self.weight = weight
# self.volume = volume
sack = Bounty( 'sack' , 0 , 25 , 42 )
items = [ Bounty( 'panacea' , 3000 , 3 , 25 ) ,
Bounty( 'ichor' , 1800 , 2 , 15 ) ,
Bounty( 'gold' , 2500 , 20 , 2 ) ]
def tot_value( items_count, items, sack) :
"""
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).
"""
weight = sum ( n * item.weight for n, item in izip( items_count, items) )
volume = sum ( n * item.volume for n, item in izip( items_count, items) )
if weight <= sack.weight and volume <= sack.volume :
return sum ( n * item.value for n, item in izip( items_count, items) ) , -weight, -volume
else :
return -1 , 0 , 0
def knapsack_dp( items, sack) :
if ( sum ( item.weight for item in items) <= sack.weight
and sum ( item.volume for item in items) <= sack.volume ) :
return [ 1 ] * len ( items)
table = [ [ 0 ] * ( sack.volume + 1 ) for i in xrange ( sack.weight + 1 ) ]
for item in items:
for w in reversed ( xrange ( sack.weight + 1 ) ) :
for v in reversed ( xrange ( sack.volume + 1 ) ) :
if w >= item.weight and v >= item.volume :
table[ w] [ v] = max ( table[ w] [ v] , 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
print table[ w] [ v]
while table[ w] [ v] :
# Find the last item that was added:
aux = [ table[ w-item.weight ] [ v-item.volume ] + item.value for item in items]
i = aux.index ( table[ w] [ v] )
# Record it in the result, and remove it:
result[ i] = 1
w -= items[ i] .weight
v -= items[ i] .volume
return result
max_items = knapsack_dp( items, sack)
max_value, max_weight, max_volume = tot_value( max_items, items, sack)
max_weight = -max_weight
max_volume = -max_volume
print "The maximum value achievable (by exhaustive search) is %g." % max_value
item_names = ", " .join ( item.name for item in items)
print " The number of %s items to achieve this is: %s, respectively." % ( item_names, max_items)
print " The weight to carry is %.3g, and the volume used is %.3g." % ( max_weight, max_volume)
ZnJvbSBpdGVydG9vbHMgaW1wb3J0IHByb2R1Y3QsIGl6aXAKZnJvbSBjb2xsZWN0aW9ucyBpbXBvcnQgbmFtZWR0dXBsZQogCkJvdW50eSA9IG5hbWVkdHVwbGUoJ0JvdW50eScsICduYW1lIHZhbHVlIHdlaWdodCB2b2x1bWUnKQogCiMgIm5hbWVkdHVwbGUiIGlzIG9ubHkgYXZhaWxhYmxlIGluIFB5dGhvbiAyLjYrOyBmb3IgZWFybGllciB2ZXJzaW9ucyB1c2UgdGhpcyBpbnN0ZWFkOgojIGNsYXNzIEJvdW50eToKIyAgICAgZGVmIF9faW5pdF9fKHNlbGYsIG5hbWUsIHZhbHVlLCB3ZWlnaHQsIHZvbHVtZSk6CiMgICAgICAgICBzZWxmLm5hbWUgPSBuYW1lCiMgICAgICAgICBzZWxmLnZhbHVlID0gdmFsdWUKIyAgICAgICAgIHNlbGYud2VpZ2h0ID0gd2VpZ2h0CiMgICAgICAgICBzZWxmLnZvbHVtZSA9IHZvbHVtZQogCnNhY2sgPSAgIEJvdW50eSgnc2FjaycsICAgICAgIDAsIDI1LCA0MikKIAppdGVtcyA9IFtCb3VudHkoJ3BhbmFjZWEnLCAzMDAwLCAgIDMsICAyNSksCiAgICAgICAgIEJvdW50eSgnaWNob3InLCAgIDE4MDAsICAgMiwgIDE1KSwKICAgICAgICAgQm91bnR5KCdnb2xkJywgICAgMjUwMCwgIDIwLCAgIDIpXQogCiAKZGVmIHRvdF92YWx1ZShpdGVtc19jb3VudCwgaXRlbXMsIHNhY2spOgogICAgIiIiCiAgICBHaXZlbiB0aGUgY291bnQgb2YgZWFjaCBpdGVtIGluIHRoZSBzYWNrIHJldHVybiAtMSBpZiB0aGV5IGNhbid0IGJlIGNhcnJpZWQgb3IgdGhlaXIgdG90YWwgdmFsdWUuCiAKICAgIChhbHNvIHJldHVybiB0aGUgbmVnYXRpdmUgb2YgdGhlIHdlaWdodCBhbmQgdGhlIHZvbHVtZSBzbyB0YWtpbmcgdGhlIG1heCBvZiBhIHNlcmllcyBvZiByZXR1cm4KICAgIHZhbHVlcyB3aWxsIG1pbmltaXNlIHRoZSB3ZWlnaHQgaWYgdmFsdWVzIHRpZSwgYW5kIG1pbmltaXNlIHRoZSB2b2x1bWUgaWYgdmFsdWVzIGFuZCB3ZWlnaHRzIHRpZSkuCiAgICAiIiIKICAgIHdlaWdodCA9IHN1bShuICogaXRlbS53ZWlnaHQgZm9yIG4sIGl0ZW0gaW4gaXppcChpdGVtc19jb3VudCwgaXRlbXMpKQogICAgdm9sdW1lID0gc3VtKG4gKiBpdGVtLnZvbHVtZSBmb3IgbiwgaXRlbSBpbiBpemlwKGl0ZW1zX2NvdW50LCBpdGVtcykpCiAgICBpZiB3ZWlnaHQgPD0gc2Fjay53ZWlnaHQgYW5kIHZvbHVtZSA8PSBzYWNrLnZvbHVtZToKICAgICAgICByZXR1cm4gc3VtKG4gKiBpdGVtLnZhbHVlIGZvciBuLCBpdGVtIGluIGl6aXAoaXRlbXNfY291bnQsIGl0ZW1zKSksIC13ZWlnaHQsIC12b2x1bWUKICAgIGVsc2U6CiAgICAgICAgcmV0dXJuIC0xLCAwLCAwCiAKIApkZWYga25hcHNhY2tfZHAoaXRlbXMsIHNhY2spOgogICAgaWYoc3VtKGl0ZW0ud2VpZ2h0IGZvciBpdGVtIGluIGl0ZW1zKSA8PSBzYWNrLndlaWdodAogICAgICAgIGFuZCBzdW0oaXRlbS52b2x1bWUgZm9yIGl0ZW0gaW4gaXRlbXMpIDw9IHNhY2sudm9sdW1lKToKICAgICAgICByZXR1cm4gWzFdICogbGVuKGl0ZW1zKQoKICAgIHRhYmxlID0gW1swXSAqIChzYWNrLnZvbHVtZSArIDEpIGZvciBpIGluIHhyYW5nZShzYWNrLndlaWdodCArIDEpXQogCQogICAgZm9yIGl0ZW0gaW4gaXRlbXM6CiAgICAgICAgZm9yIHcgaW4gcmV2ZXJzZWQoeHJhbmdlKHNhY2sud2VpZ2h0ICsgMSkpOgogICAgICAgICAgICBmb3IgdiBpbiByZXZlcnNlZCh4cmFuZ2Uoc2Fjay52b2x1bWUgKyAxKSk6CiAgICAgICAgICAgICAgICBpZiB3ID49IGl0ZW0ud2VpZ2h0IGFuZCB2ID49IGl0ZW0udm9sdW1lOgogICAgICAgICAgICAgICAgICAgIHRhYmxlW3ddW3ZdID0gbWF4KHRhYmxlW3ddW3ZdLCB0YWJsZVt3IC0gaXRlbS53ZWlnaHRdW3YgLSBpdGVtLnZvbHVtZV0gKyBpdGVtLnZhbHVlKQogCiAgICAjIEJhY2t0cmFjayB0aHJvdWdoIG1hdHJpeCB0byByZS1jb25zdHJ1Y3Qgb3B0aW11bToKICAgIHJlc3VsdCA9IFswXSAqIGxlbihpdGVtcykKICAgIHcgPSBzYWNrLndlaWdodAogICAgdiA9IHNhY2sudm9sdW1lCiAgICBwcmludCB0YWJsZVt3XVt2XQogICAgd2hpbGUgdGFibGVbd11bdl06CiAgICAgICAgIyBGaW5kIHRoZSBsYXN0IGl0ZW0gdGhhdCB3YXMgYWRkZWQ6CiAgICAgICAgYXV4ID0gW3RhYmxlW3ctaXRlbS53ZWlnaHRdW3YtaXRlbS52b2x1bWVdICsgaXRlbS52YWx1ZSBmb3IgaXRlbSBpbiBpdGVtc10KICAgICAgICBpID0gYXV4LmluZGV4KHRhYmxlW3ddW3ZdKQogCiAgICAgICAgIyBSZWNvcmQgaXQgaW4gdGhlIHJlc3VsdCwgYW5kIHJlbW92ZSBpdDoKICAgICAgICByZXN1bHRbaV0gPSAxCiAgICAgICAgdyAtPSBpdGVtc1tpXS53ZWlnaHQKICAgICAgICB2IC09IGl0ZW1zW2ldLnZvbHVtZQogCiAgICByZXR1cm4gcmVzdWx0CiAKIAptYXhfaXRlbXMgPSBrbmFwc2Fja19kcChpdGVtcywgc2FjaykKbWF4X3ZhbHVlLCBtYXhfd2VpZ2h0LCBtYXhfdm9sdW1lID0gdG90X3ZhbHVlKG1heF9pdGVtcywgaXRlbXMsIHNhY2spCm1heF93ZWlnaHQgPSAtbWF4X3dlaWdodAptYXhfdm9sdW1lID0gLW1heF92b2x1bWUKIApwcmludCAiVGhlIG1heGltdW0gdmFsdWUgYWNoaWV2YWJsZSAoYnkgZXhoYXVzdGl2ZSBzZWFyY2gpIGlzICVnLiIgJSBtYXhfdmFsdWUKaXRlbV9uYW1lcyA9ICIsICIuam9pbihpdGVtLm5hbWUgZm9yIGl0ZW0gaW4gaXRlbXMpCnByaW50ICIgIFRoZSBudW1iZXIgb2YgJXMgaXRlbXMgdG8gYWNoaWV2ZSB0aGlzIGlzOiAlcywgcmVzcGVjdGl2ZWx5LiIgJSAoaXRlbV9uYW1lcywgbWF4X2l0ZW1zKQpwcmludCAiICBUaGUgd2VpZ2h0IHRvIGNhcnJ5IGlzICUuM2csIGFuZCB0aGUgdm9sdW1lIHVzZWQgaXMgJS4zZy4iICUgKG1heF93ZWlnaHQsIG1heF92b2x1bWUp