-
Notifications
You must be signed in to change notification settings - Fork 0
/
w5l801_knapsack.py
151 lines (132 loc) · 4.43 KB
/
w5l801_knapsack.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import pylab
class Item(object):
def __init__(self, n, v, w):
self.name = n
self.value = float(v)
self.weight = float(w)
def getName(self):
return self.name
def getValue(self):
return self.value
def getWeight(self):
return self.weight
def __str__(self):
result = '<' + self.name + ', ' + str(self.value) + ', '\
+ str(self.weight) + '>'
return result
def buildItems():
names = ['clock', 'painting', 'radio', 'vase', 'book',
'computer']
vals = [175,90,20,50,10,200]
weights = [10,9,4,2,1,20]
Items = []
for i in range(len(vals)):
Items.append(Item(names[i], vals[i], weights[i]))
return Items
def greedy(Items, maxWeight, keyFcn):
assert type(Items) == list and maxWeight >= 0
ItemsCopy = sorted(Items, key=keyFcn, reverse = True)
result = []
totalVal = 0.0
totalWeight = 0.0
i = 0
while totalWeight < maxWeight and i < len(Items):
if (totalWeight + ItemsCopy[i].getWeight()) <= maxWeight:
result.append((ItemsCopy[i]))
totalWeight += ItemsCopy[i].getWeight()
totalVal += ItemsCopy[i].getValue()
i += 1
return (result, totalVal)
def value(item):
return item.getValue()
def weightInverse(item):
return 1.0/item.getWeight()
def density(item):
return item.getValue()/item.getWeight()
def testGreedy(Items, constraint, getKey):
taken, val = greedy(Items, constraint, getKey)
print ('Total value of items taken = ' + str(val))
for item in taken:
print ' ', item
def testGreedys(maxWeight = 20):
Items = buildItems()
print('Items to choose from:')
for item in Items:
print ' ', item
print 'Use greedy by value to fill a knapsack of size', maxWeight
testGreedy(Items, maxWeight, value)
print 'Use greedy by weight to fill a knapsack of size', maxWeight
testGreedy(Items, maxWeight, weightInverse)
print 'Use greedy by density to fill a knapsack of size', maxWeight
testGreedy(Items, maxWeight, density)
def dToB(n, numDigits):
"""requires: n is a natural number less than 2**numDigits
returns a binary string of length numDigits representing the
the decimal number n."""
assert type(n)==int and type(numDigits)==int and n >=0 and n < 2**numDigits
bStr = ''
while n > 0:
bStr = str(n % 2) + bStr
n = n//2 #divide exactly
while numDigits - len(bStr) > 0:
bStr = '0' + bStr
return bStr
def genPset(Items):
"""Generate a list of lists representing the power set of Items"""
numSubsets = 2**len(Items)
templates = []
for i in range(numSubsets):
templates.append(dToB(i, len(Items)))
pset = []
for t in templates:
elem = []
for j in range(len(t)):
if t[j] == '1':
elem.append(Items[j])
pset.append(elem)
return pset
def chooseBest(pset, constraint, getVal, getWeight):
bestVal = 0.0
bestSet = None
for Items in pset:
ItemsVal = 0.0
ItemsWeight = 0.0
for item in Items:
ItemsVal += getVal(item)
ItemsWeight += getWeight(item)
if ItemsWeight <= constraint and ItemsVal > bestVal:
bestVal = ItemsVal
bestSet = Items
return (bestSet, bestVal)
def testBest():
Items = buildItems()
pset = genPset(Items)
taken, val = chooseBest(pset, 20, Item.getValue, Item.getWeight)
print ('Total value of items taken = ' + str(val))
for item in taken:
print ' ', item
def maxVal(toConsider, avail):
if toConsider == [] or avail == 0:
result = (0, ())
elif toConsider[0].getWeight() > avail:
result = maxVal(toConsider[1:], avail)
else:
nextItem = toConsider[0]
#Explore left branch
withVal, withToTake = maxVal(toConsider[1:],
avail - nextItem.getWeight())
withVal += nextItem.getValue()
#Explore right branch
withoutVal, withoutToTake = maxVal(toConsider[1:], avail)
#Choose better branch
if withVal > withoutVal:
result = (withVal, withToTake + (nextItem,))
else:
result = (withoutVal, withoutToTake)
return result
def smallTest():
Items = buildItems()
val, taken = maxVal(Items, 20)
for item in taken:
print(item)
print ('Total value of items taken = ' + str(val))