Dynamic Programming | Set 22 (Box Stacking Problem)
You are given a set of n types of rectangular 3-D boxes, where the i^th box has height h(i), width w(i) and depth d(i) (all real numbers). You want to create a stack of boxes which is as tall as possible, but you can only stack a box on top of another box if the dimensions of the 2-D base of the lower box are each strictly larger than those of the 2-D base of the higher box. Of course, you can rotate a box so that any side functions as its base. It is also allowable to use multiple instances of the same type of box.
Source: http://people.csail.mit.edu/bdean/6.046/dp/. The link also has video for explanation of solution.
The Box Stacking problem is a variation of LIS problem. We need to build a maximum height stack.
Following are the key points to note in the problem statement:
1) A box can be placed on top of another box only if both width and depth of the upper placed box are smaller than width and depth of the lower box respectively.
2) We can rotate boxes. For example, if there is a box with dimensions {1x2x3} where 1 is height, 2×3 is base, then there can be three possibilities, {1x2x3}, {2x1x3} and {3x1x2}.
3) We can use multiple instances of boxes. What it means is, we can have two different rotations of a box as part of our maximum height stack.
Following is the solution based on DP solution of LIS problem.
1) Generate all 3 rotations of all boxes. The size of rotation array becomes 3 times the size of original array. For simplicity, we consider depth as always smaller than or equal to width.
2) Sort the above generated 3n boxes in decreasing order of base area.
3) After sorting the boxes, the problem is same as LIS with following optimal substructure property.
MSH(i) = Maximum possible Stack Height with box i at top of stack
MSH(i) = { Max ( MSH(j) ) + height(i) } where j < i and width(j) > width(i) and depth(j) > depth(i).
If there is no such j then MSH(i) = height(i)
4) To get overall maximum height, we return max(MSH(i)) where 0 < i < n
Following is C++ implementation of the above solution.
/* Dynamic Programming implementation of Box Stacking problem */
#include<stdio.h>
#include<stdlib.h>
/* Representation of a box */
struct Box
{
// h –> height, w –> width, d –> depth
int h, w, d; // for simplicity of solution, always keep w <= d
};
// A utility function to get minimum of two intgers
int min (int x, int y)
{ return (x < y)? x : y; }
// A utility function to get maximum of two intgers
int max (int x, int y)
{ return (x > y)? x : y; }
/* Following function is needed for library function qsort(). We
use qsort() to sort boxes in decreasing order of base area.
Refer following link for help of qsort() and compare()
http://www.cplusplus.com/reference/clibrary/cstdlib/qsort/ */
int compare (const void *a, const void * b)
{
return ( (*(Box *)b).d * (*(Box *)b).w ) -
( (*(Box *)a).d * (*(Box *)a).w );
}
/* Returns the height of the tallest stack that can be formed with give type of boxes */
int maxStackHeight( Box arr[], int n )
{
/* Create an array of all rotations of given boxes
For example, for a box {1, 2, 3}, we consider three
instances{{1, 2, 3}, {2, 1, 3}, {3, 1, 2}} */
Box rot[3*n];
int index = 0;
for (int i = 0; i < n; i++)
{
// Copy the original box
rot[index] = arr[i];
index++;
// First rotation of box
rot[index].h = arr[i].w;
rot[index].d = max(arr[i].h, arr[i].d);
rot[index].w = min(arr[i].h, arr[i].d);
index++;
// Second rotation of box
rot[index].h = arr[i].d;
rot[index].d = max(arr[i].h, arr[i].w);
rot[index].w = min(arr[i].h, arr[i].w);
index++;
}
// Now the number of boxes is 3n
n = 3*n;
/* Sort the array ‘rot[]‘ in decreasing order, using library
function for quick sort */
qsort (rot, n, sizeof(rot[0]), compare);
// Uncomment following two lines to print all rotations
// for (int i = 0; i < n; i++ )
// printf("%d x %d x %d\n", rot[i].h, rot[i].w, rot[i].d);
/* Initialize msh values for all indexes
msh[i] –> Maximum possible Stack Height with box i on top */
int msh[n];
for (int i = 0; i < n; i++ )
msh[i] = rot[i].h;
/* Compute optimized msh values in bottom up manner */
for (int i = 1; i < n; i++ )
for (int j = 0; j < i; j++ )
if ( rot[i].w < rot[j].w &&
rot[i].d < rot[j].d &&
msh[i] < msh[j] + rot[i].h
)
{
msh[i] = msh[j] + rot[i].h;
}
/* Pick maximum of all msh values */
int max = -1;
for ( int i = 0; i < n; i++ )
if ( max < msh[i] )
max = msh[i];
return max;
}
/* Driver program to test above function */
int main()
{
Box arr[] = { {4, 6, 7}, {1, 2, 3}, {4, 5, 6}, {10, 12, 32} };
int n = sizeof(arr)/sizeof(arr[0]);
printf("The maximum possible height of stack is %d\n",
maxStackHeight (arr, n) );
return 0;
}
Output:
The maximum possible height of stack is 60
In the above program, given input boxes are {4, 6, 7}, {1, 2, 3}, {4, 5, 6}, {10, 12, 32}. Following are all rotations of the boxes in decreasing order of base area.
10 x 12 x 32 12 x 10 x 32 32 x 10 x 12 4 x 6 x 7 4 x 5 x 6 6 x 4 x 7 5 x 4 x 6 7 x 4 x 6 6 x 4 x 5 1 x 2 x 3 2 x 1 x 3 3 x 1 x 2
The height 60 is obtained by boxes { {3, 1, 2}, {1, 2, 3}, {6, 4, 5}, {4, 5, 6}, {4, 6, 7}, {32, 10, 12}, {10, 12, 32}}
Time Complexity: O(n^2)
Auxiliary Space: O(n)
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.

Does the solution ensures that every box will be used atleast once?
Hi,
Does the output is 60 or 50?
I can't test the C code now. I made some changes to Java.
Arrays.sort(rot); ... public int compareTo(Box b) { int diff = b.d * b.w - this.d * this.w; if(diff > 0) return 1; if(diff < 0) return -1; return 0; } ...Admin, please explain why you have 1 box coming multiple times in the answer(with dimensions interchanged.
Question doesnt say you can do this
Please take a closer look at the question, especially following lines.
Of course, you can rotate a box so that any side functions as its base. It is also allowable to use multiple instances of the same type of box.
In conditional part :
/* if ( rot[i].w < rot[j].w && rot[i].d < rot[j].d && msh[i] < msh[j] + rot[i].h ) { msh[i] = msh[j] + rot[i].h; } */I think this expression should be modified as :
/* if (( rot[i].w < rot[j].w&&rot[i].d < rot[j].d )||( rot[i].w < rot[j].d&&rot[i].d < rot[j].w )&& msh[i] < msh[j] + rot[i].h ) { msh[i] = msh[j] + rot[i].h; } */Please correct me if I am wrong ..
What is the significance of sorting according to decreasing base area ? I think it should be enough to srt by depth or width.
Even if we sort the boxes just on the basis of length ..I know that the answer is a increasing sub sequence of the boxes sorted by length ..
Is there any reason that we need to sort by base area? or am i missing some thing
Please correct me if I am wrong ...
How can we implemen2 ds program in C?
How do we print the boxes which gives us the maximum height of the stack?
Your code gives wrong output for the following set,
{{5,2,4},{1,4,2},{4,4,2}}
Correct output should be 13 where as your code shows 11.
Any reason for this?
For simplicity we can write above set as,
{{5,2,4},{1,2,4},{4,2,4}} where w <= d
11 is the correct answer. Please take a closer look at the problem statement. The width and length of a lower box must be strictly smaller than the upper box. And we can take more than one instances of a box.
Following are all possible rotations where first column is height. Highlighted boxes are selected for maximum height 11.
2 x 4 x 5
2 x 4 x 4
4 x 2 x 5
1 x 4 x 2
5 x 2 x 4
4 x 2 x 4
4 x 4 x 2
2 x 1 x 4
4 x 1 x 2
What if we are allowed to have 1 instance per box. Can you suggest what to change?
Please reply the whoru question
What if we are allowed to have 1 instance per box ?
I think , it will make problem hard...
Yes , it would be very difficult if only 1 instance of box is allowed ,as sorting will not work in that case , because it is very possible that there may be different box instances between 2 rotations of same box instances , so it may be that same box instance already used in solution ......waiting for reply for correct solution......
Why do we need the sort ?
After sorting the boxes by base dimensions, the maximum possible height of the stack will be all elements put in (in the same order of sorting), right?
Why do we need to do make a LIS out of it?
I think, I didn't understand the problem clearly.
If it was allowed to place boxes with smaller base area over larger base area even if 1 side had the same dimension, then this solution would not work. Right?
I think this is wrong :
1) A box can be placed on top of another box only if both width and depth of the upper placed box are greater than width and depth of the lower box respectively.
It should be - smaller than
Thanks for pointing this out. There was a typo in explanation. We will change it soon. The code and other explanation remains same.
Corrected!
* MSH(i) = { Max ( MSH(j) ) + height(i) } where j width(i) and height(j) > height(i).
I think it should be
MSH(i) = { Max ( MSH(j) ) + height(i) } where j width(i) and depth(j) > depth(i).
@rahul: Thanks for pointing this out. We have corrected the expression.