I am trying to select at most 10 items from this list to get the higher possible profit.
Item name | Item "Weight" | Item "Profit"
[A, 1084, 424],
[B, 1143, 391],
[C, 1205, 351],
[D, 1088, 328],
[E, 5, 21],
[F, 996, 241],
[G, 13, 23],
[H, 2, 9],
[I, 5, 13],
[J, 14, 21],
[K, 11, 18],
[L, 4, 12],
[M, 121, 59],
...
Total length: 249
I found that my problem could be defined as a 0/1 Bidimensional Knapsack problem . Weight would be the first dimension, and the 10 items limit would be the second dimension. So I tried different solutions with python to optimize the selection.
After searching different sources, I was not able to found a python solution to my specific problem:
Finally I found this java solution that I have tried to translate, but a made a mistake somewhere, the function works almost properly but it fails to find a correct solution. I have spent a couple of days trying to find where the code fails, but it is somewhat confusing.
from collections import namedtuple
Bounty = namedtuple('Bounty', 'name value size volume')
sack = Bounty('sack', value=0, size=800, volume=10)
items = results #A big list as mentioned above
dynNoRep = [[[0 for k in xrange(sack.volume+1)] for j in xrange(sack.size+1)] for i in xrange(
len(items) + 1)]
for i,item in enumerate(items):
for j in range(sack.size):
for h in range(sack.volume):
if item.size > j:
#pdb.set_trace()
dynNoRep[i][j][h] = dynNoRep[i-1][j][h]
elif item.volume > h:
dynNoRep[i][j][h] = dynNoRep[i-1][j][h]
else:
dynNoRep[i][j][h] = max(
dynNoRep[i-1][j][h], dynNoRep[i-1][j - items[i-1].size][h - items[i-1].volume] + items[i-1].value)
for i,item in enumerate(items):
for j in range(sack.size):
dynNoRep[i][j][sack.volume] = dynNoRep[i][j][sack.volume-1]
j = sack.size
h = sack.volume
finalSize = 0
finalValue = 0
finalVolume = 0
for i in range(len(items)-1, -1, -1):
#pdb.set_trace()
if dynNoRep[i][j][h] != dynNoRep[i-1][j][h]:
print"Value {} | Size {} | Volume {}".format(str(items[i-1].value), str(items[i-1].size), str(items[i-1].volume))
finalSize += items[i-1].size
finalValue += items[i-1].value
finalVolume += items[i-1].volume
j -= items[i - 1].size
h -= items[i - 1].volume
print('Final size {} / {}'.format(str(finalSize), str(sack.size)))
print('Final volume {} / {}'.format(str(finalVolume), str(sack.volume)))
print('Final value {}'.format(str(finalValue)))
And this is the output, sometimes it show something nicer, but never the correct solution:
Final size 0 / 800
Final volume 0 / 10
Final value 0
Context: Windows 8.1 32 bits. Ipython notebook. Python 2.
Any suggestions to make the code works? Thank you in advance!
Finally it was easier to use Cython inside ipython, "translating" a C++ algorithm found here .
Here is the needed import:
%load_ext Cython
Be sure to install the cython extension first.
Here is the "Cython" version of the code in the previous link:
%%cython
from libc.string cimport memset
cdef int noOfItems, maxWeight, maxItems
cdef int items[100]
cdef int value[100]
cdef int dp[100][1000][100]
cdef int solve(int idx, int currentWeight, int itemsLeft, noOfItems):
if idx == noOfItems or itemsLeft == 0:
return 0
if dp[idx][currentWeight][itemsLeft] != -1:
return dp[idx][currentWeight][itemsLeft]
cdef int v1 = 0
cdef int v2 = 0
if currentWeight >= items[idx]:
v1 = solve(idx+1, currentWeight-items[idx], itemsLeft-1, noOfItems) + value[idx]
v2 = solve(idx+1, currentWeight, itemsLeft, noOfItems)
dp[idx][currentWeight][itemsLeft] = max(v1, v2)
return dp[idx][currentWeight][itemsLeft]
cdef void printer(int idx, int currentWeight, int itemsLeft, noOfItems):
if idx == noOfItems or itemsLeft == 0:
return
cdef int v1 = 0
cdef int v2 = 0
if currentWeight >= items[idx]:
v1 = solve(idx+1, currentWeight-items[idx], itemsLeft-1, noOfItems) + value[idx]
v2 = solve(idx+1, currentWeight, itemsLeft, noOfItems)
if v1 >= v2:
print(items[idx], value[idx])
printer(idx+1, currentWeight-items[idx], itemsLeft-1, noOfItems)
return
else:
printer(idx+1, currentWeight, itemsLeft, noOfItems)
return
cdef knapsack(lenitems, maxWeight, maxItems):
noOfItems = lenitems
maxWeight = 15
maxItems = 3
pairs = [[4,6], [3,4], [5, 5], [7, 3], [7, 7]]
for i in range(noOfItems):
items[i] = pairs[i][0]
value[i] = pairs[i][1]
memset(dp, -1, sizeof(dp))
print(solve(0, maxWeight, maxItems, noOfItems))
print "Printing the elements in the knapsack"
printer(0, maxWeight, maxItems, noOfItems)
def pyknapsack(lenitems, maxWeight=15, maxItems=3):
print 'Hao'
knapsack(lenitems, maxWeight, maxItems)
The pyknapsack function is a python "wrapper" so you could use the C functions inside python.
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.