I need to write a program that finds the maximum number of boxes that can be stacked up according to the below constraints.
We have some boxes labeled 1 to N. The dimensions of all cartons are identical. Now we have to stack up some of the boxes, subject to the following constraints:
Here are given HINTS:
I have already made a 0-1 knapsack code, but I don't know how to tweak it, given the hints above.
public static int knapsack(int costs[], int values[], int capacity, int index) {
if(capacity =z= 0) {
return 0;
}
if(index == 0) {
if(capacity >= costs[0]) {
return values[0];
}
return 0;
}
if(knapsackMemo[capacity][index] != -1) {
return knapsackMemo[capacity][index];
}
//Choice 1: If added to knapsack
int choice1 = -1;
if(capacity >= costs[index]) {
choice1 = knapsack(costs, values, capacity - costs[index], index - 1) + values[index];
}
//Choice 2: If not added to knapsack
int choice2 = knapsack(costs, values, capacity, index - 1);
knapsackMemo[capacity][index] = Math.max(choice1, choice2);
return knapsackMemo[capacity][index];
}
Here is my main method:
public static void main(String[] args) {
int budget = 6000;
int loads[] = {15, 13, 7, 8, 2};
int weights[] = {19, 7, 5, 6, 1};
int index = 0;
System.out.println(knapsack(weights, loads, budget, index));
}
Problem clarification (attempt :) )
I'll not directly comment your code but I'll first try to explain the constraints and hints a little (at least how I understand them) to make it easier for you:
C1: One cannot put more than one box directly upon a box;
That means you basically build a tower (hence the hints use "tower" and "subtower") of boxes that can carry a limited amount of additional weigth aka 'load'.
C2: Boxes with lower load labels are not to be put upon one with a higher load;
H3: For each box, you have two choices: either to include the box in the stack (if possible), or skip the box.
That means you the boxes are ordered or can be ordered and thus iterated upon (order them by their maximum load). Let's say you have 3 boxes (already ordered): box1 with a load of 15, box2 with a load of 12 and box3 with a load of 10. Since box1 cannot be stacked on box2 or box3 (due to C2), you either decide to include box1 in the tower or skip it (and don't use it). Thus you'd just have to keep a list of which box numbers have been added to a certain (partial) solution so far.
C3: The weight and maximum load for each box are given. The total weight of all boxes upon a box should not exceed its maximum load.
H4: When including a box in the stack, the load limit of the subproblem tower will be updated. The new load limit is the minimum of two values (that you have to determine).
The empty tower already has a maximum capacity which then will be reduced with each box added. Since each box can have a lower load the maximum weight for all additional boxes on top of that will be the minimum of the tower's rest capacity and the maximum load of the highest box.
Example: Suppose your current tower has a rest capacity of 50. You now add a box of weight 10 and a maximum additional load of 25. The rest capacity of the tower now is min(restCapacity - boxWeight, boxMaxLoad)
or min(50 - 10, 25) = min(40,25) = 25
.
Comments on your code
With the information above and your main method you seem to already have an almost ordered list of boxes (boxes 3 and 4 would have to be swapped). The array weights
seems to define the weight of each box while Loads
(which should be named loads
btw) would define the additional load each box can take.
That being said you shouldn't iterate backwards (i.e. from length - 1 to 0) but forward (i.e. from 0 to length - 1).
Additionally you should rename your parameters to avoid confusion and also put the type information together. So instead of knapsack(int costs[], int values[], int capacity, int index)
you should do something like knapsack(int[] weights, int[] loads, int capacity, int index)
.
The algorithm itself is basically like traversing a binary tree: you branch into "add" or "skip" until you're out of boxes, hit the current capacity or exceed it (in which case you need to backtrack). Then you count each "add" step taken and backtracking would mean you cancel the last "add" - since that can only happen if you added a new box.
The code could then look like that:
int knapsack(int weights[], int loads[], int capacity, int index) {
//no more boxes or exactly out of capacity, return 0 additional boxes
if( index >= weights.length || capacity == 0) {
return 0;
}
//capacity exceeded, we need to remove the previous box so we return -1
if( capacity < 0 ) {
return -1;
}
//"add" branch: since we added 1 box we add 1 to the result of the subtree
//(which could be -1 if we exceeded the capacity and thus the result would be 0).
int resultIfAdded = knapsack(weights, loads,
//the rest capacity is the current capacity minus the current box' weight
//or the current box' load if it is lower
Math.min( capacity - weights[index], loads[index]),
index + 1 ) + 1;
//"skip" branch, we just increase the index
int resultIfSkipped = knapsack(weights, loads, capacity, index + 1 );
//we want the highest number of boxes we can stack so return the maximum of both branches
return Math.max( resultIfAdded, resultIfSkipped );
}