package com.interview.dynamic; import java.util.Arrays; /** * Date 05/09/2015 * @author tusroy * * Given different dimensions and unlimited supply of boxes for each dimension, stack boxes * on top of each other such that it has maximum height but with caveat that length and width * of box on top should be strictly less than length and width of box under it. You can * rotate boxes as you like. * * 1) Create all rotations of boxes such that length is always greater or equal to width * 2) Sort boxes by base area in non increasing order (length * width). This is because box * with more area will never ever go on top of box with less area. * 3) Take T[] and result[] array of same size as total boxes after all rotations are done * 4) Apply longest increasing subsequence type of algorithm to get max height. * * If n number of dimensions are given total boxes after rotation will be 3n. * So space complexity is O(n) * Time complexity - O(nlogn) to sort boxes. O(n^2) to apply DP on it So really O(n^2) * * References * http://www.geeksforgeeks.org/dynamic-programming-set-21-box-stacking-problem/ * http://people.cs.clemson.edu/~bcdean/dp_practice/ */ public class BoxStacking { public int maxHeight(Dimension[] input) { //get all rotations of box dimension. //e.g if dimension is 1,2,3 rotations will be 2,1,3 3,2,1 3,1,2 . Here length is always greater //or equal to width and we can do that without loss of generality. Dimension[] allRotationInput = new Dimension[input.length * 3]; createAllRotation(input, allRotationInput); //sort these boxes in non increasing order by their base area.(length X width) Arrays.sort(allRotationInput); //apply longest increasing subsequence kind of algorithm on these sorted boxes. int T[] = new int[allRotationInput.length]; int result[] = new int[allRotationInput.length]; for (int i = 0; i < T.length; i++) { T[i] = allRotationInput[i].height; result[i] = i; } for (int i = 1; i < T.length; i++) { for (int j = 0; j < i; j++) { if (allRotationInput[i].length < allRotationInput[j].length && allRotationInput[i].width < allRotationInput[j].width) { if( T[j] + allRotationInput[i].height > T[i]){ T[i] = T[j] + allRotationInput[i].height; result[i] = j; } } } } //find max in T[] and that will be our max height. //Result can also be found using result[] array. int max = Integer.MIN_VALUE; for(int i=0; i < T.length; i++){ if(T[i] > max){ max = T[i]; } } return max; } //create all rotations of boxes, always keeping length greater or equal to width private void createAllRotation(Dimension[] input, Dimension[] allRotationInput) { int index = 0; for (int i = 0; i < input.length; i++) { allRotationInput[index++] = Dimension.createDimension( input[i].height, input[i].length, input[i].width); allRotationInput[index++] = Dimension.createDimension( input[i].length, input[i].height, input[i].width); allRotationInput[index++] = Dimension.createDimension( input[i].width, input[i].length, input[i].height); } } public static void main(String args[]) { BoxStacking bs = new BoxStacking(); Dimension input[] = { new Dimension(3, 2, 5), new Dimension(1, 2, 4) }; int maxHeight = bs.maxHeight(input); System.out.println("Max height is " + maxHeight); assert 11 == maxHeight; } } /** * Utility class to hold dimensions * @author tusroy * */ class Dimension implements Comparable<Dimension> { int height; int length; int width; Dimension(int height, int length, int width) { this.height = height; this.length = length; this.width = width; } Dimension() { } static Dimension createDimension(int height, int side1, int side2) { Dimension d = new Dimension(); d.height = height; if (side1 >= side2) { d.length = side1; d.width = side2; } else { d.length = side2; d.width = side1; } return d; } /** * Sorts by base area(length X width) */ @Override public int compareTo(Dimension d) { if (this.length * this.width >= d.length * d.width) { return -1; } else { return 1; } } @Override public String toString() { return "Dimension [height=" + height + ", length=" + length + ", width=" + width + "]"; } }