|
| 1 | + |
| 2 | +# coding: utf-8 |
| 3 | + |
| 4 | +# In[1]: |
| 5 | + |
| 6 | + |
| 7 | +#this is a more advanced knapsack problem |
| 8 | +#we have a new variable called groups |
| 9 | +#we are only allowed to select at most one item from each group |
| 10 | +#please note julia version is a lot more complex than python version |
| 11 | +#simply becuz julia starts index at 1 and doesnt allow negative number indexing |
| 12 | +#please check the following link for the basic knapsack problem |
| 13 | +# https://github.com/je-suis-tm/recursion-and-dynamic-programming/blob/master/knapsack.jl |
| 14 | + |
| 15 | + |
| 16 | +# In[2]: |
| 17 | + |
| 18 | + |
| 19 | +#solve multiple choice knapsack via dynamic programming |
| 20 | +function knapsack_multichoice(total_weight,values,weights,groups) |
| 21 | + |
| 22 | + #julia starts index at 1 which is why we use length(values) |
| 23 | + #create a nested list with size of number of items*weights |
| 24 | + array=[[0 for _ in 1:total_weight] for _ in 1:length(values)] |
| 25 | + path=[[[] for _ in 1:total_weight] for _ in 1:length(values)] |
| 26 | + |
| 27 | + #now we begin our traversal on all elements in matrix |
| 28 | + for i in 1:length(values) |
| 29 | + for j in 1:total_weight |
| 30 | + |
| 31 | + #-1 doesnt work as index in julia |
| 32 | + #have to find a way to get around |
| 33 | + if i==1 |
| 34 | + if weights[1]<=j |
| 35 | + array[1][j]=values[1] |
| 36 | + path[1][j]=[1] |
| 37 | + end |
| 38 | + continue |
| 39 | + end |
| 40 | + |
| 41 | + #this is the part to check if adding item i would exceed the current capacity j |
| 42 | + #if it does,we go to the previous status |
| 43 | + #if not,we shall find out whether adding item i would be the new optimal |
| 44 | + if weights[i]<j |
| 45 | + |
| 46 | + #initialize |
| 47 | + subset_max=0 |
| 48 | + target=1 |
| 49 | + |
| 50 | + #we only select one item from each group |
| 51 | + #we will find the item that maximizes the value in each group |
| 52 | + prev_group=groups[i]-1 |
| 53 | + |
| 54 | + #get column of the matrix |
| 55 | + subset=[row[j-weights[i]] for row in array] |
| 56 | + |
| 57 | + #find the item that maximizes the value in the previous group |
| 58 | + for k in 1:length(values) |
| 59 | + if groups[k]==prev_group && subset[k]>subset_max |
| 60 | + subset_max=subset[k] |
| 61 | + target=k |
| 62 | + end |
| 63 | + end |
| 64 | + |
| 65 | + #dynamic programming |
| 66 | + if subset_max+values[i]>array[i-1][j] |
| 67 | + array[i][j]=subset_max+values[i] |
| 68 | + path[i][j]=[path[target][j-weights[i]];[i]] |
| 69 | + elseif subset_max+values[i]==array[i-1][j] && weights[i]<weights[path[i-1][j][end]] |
| 70 | + array[i][j]=subset_max+values[i] |
| 71 | + path[i][j]=[path[target][j-weights[i]];[i]] |
| 72 | + else |
| 73 | + array[i][j]=array[i-1][j] |
| 74 | + path[i][j]=path[i-1][j] |
| 75 | + end |
| 76 | + |
| 77 | + elseif weights[i]==j |
| 78 | + |
| 79 | + #dynamic programming |
| 80 | + if values[i]>array[i-1][j] |
| 81 | + array[i][j]=values[i] |
| 82 | + path[i][j]=[i] |
| 83 | + elseif values[i]==array[i-1][j] && weights[i]<weights[path[i-1][j][end]] |
| 84 | + array[i][j]=values[i] |
| 85 | + path[i][j]=[i] |
| 86 | + else |
| 87 | + array[i][j]=array[i-1][j] |
| 88 | + path[i][j]=path[i-1][j] |
| 89 | + end |
| 90 | + |
| 91 | + else |
| 92 | + array[i][j]=array[i-1][j] |
| 93 | + path[i][j]=path[i-1][j] |
| 94 | + end |
| 95 | + end |
| 96 | + end |
| 97 | + return array,path |
| 98 | +end |
| 99 | + |
| 100 | + |
| 101 | +# In[3]: |
| 102 | + |
| 103 | + |
| 104 | +#a simple test |
| 105 | +values=[60,80,100,110,120,150] |
| 106 | +weights=[10,15,20,25,30,35] |
| 107 | +groups=[0,0,1,1,2,2] |
| 108 | +total_weight=50 |
| 109 | + |
| 110 | + |
| 111 | +# In[4]: |
| 112 | + |
| 113 | + |
| 114 | +array,path=knapsack_multichoice(total_weight,values, |
| 115 | + weights,groups) |
| 116 | + |
| 117 | +println(array[length(weights)][total_weight]) |
| 118 | +println(path[length(weights)][total_weight]) |
| 119 | + |
| 120 | + |
0 commit comments