简体   繁体   中英

How do I tweak my 0-1 knapsack code with the following constraints [JAVA]

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:

  1. One cannot put more than one box directly upon a table;
  2. Boxes with lower load labels are not to be placed upon one with a higher load;
  3. 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.

Here are given HINTS:

  1. This problem is similar to the knapsack problem.
  2. The parameters for the problem are the current index and the current load limit for the whole tower.
  3. For each box, you have two choices: to include the box in the stack (if possible), or skip the box.
  4. When adding 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).
  5. To solve the original problem, a good starting load limit for the tower (initially there are no boxes stacked yet) is 6000 (since the maximum weight of a box given in the input is 3000).

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 (ie from length - 1 to 0) but forward (ie 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 );
}

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM