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.
solution: I found the below solution at http://www.geeksforgeeks.org/dynamic-programming-set-21-box-stacking-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
I think the solution is wrong as it just considers 3 rotation of all the boxes. To get the correct solution, it should generate 6 possible rotations. So, is the given solution incorrect, or is their any flaw in using 6 rotations?
Note this:
For simplicity, we consider depth as always smaller than or equal to width.
So, if the dimensions of a box are, for example, 3, 4 and 5, we consider the following three ways to put it on the stack:
d=3, w=4, h=5
d=3, w=5, h=4
d=4, w=5, h=3
The other three rotations have depth larger than width, so we do not consider them:
d=4, w=3, h=5
d=5, w=3, h=4
d=5, w=4, h=3
In order to see if one rectangle a x b can be fully covered by another one c x d, it is sufficient to turn them both so that a <= b and c <= d, and then check whether a <= c and b <= d. That's why it works.
No, it's sufficient to consider 3 "rotations" of each box, because the only possibilities to consider are which dimension to make the top and bottom (say) of the box perpendicular to, and there are only 3 of these. It might help to think of the 3 different possibilities for each box in that way, instead of as rotations.
The main point is that, after we have chosen which pair of sides of a box will be top and bottom (which we can do in 3 ways), we don't need to try the 2 different rotations of the box in the plane. We can always just go with (say) the rotation in which the box is wider than it is deep. How do we know that we won't miss any potentially good solutions by doing this? Because in any solution having a box that is deeper than it is wide, there must be a lowest such box b, and that box, plus everything above it, can be safely rotated 90 degrees. (We know it's safe to do this because it's the lowest such box in the solution -- so the box underneath it, if any, must itself be wider than it is deep, meaning that if we rotate b 90 degrees, it must still fit inside this lower box (I recommend verifying this algebraically).) We can keep transforming the lowest deeper-than-it-is-wide box in the solution until none remain, without ever changing the height of the solution. Since we can do this for any solution containing one or more deeper-than-it-is-wide boxes, it means that each one is exactly equivalent in quality to some solution in which every box is wider-than-it-is-deep, so we can totally ignore the former solutions.
Related
I am trying to find an optimal way to place a set of ranges in a larger range. I like to think of it as flat boxes that can move left or right. Some things to consider:
There are N boxes, each of them with a center point Ci.
There are N attractor points (one per box), we can call them Pi. Each box is attracted to one attractor point with a force proportional to the distance.
The order of the boxes is fixed. The order of the attractor points and of the boxes is the same. So C1 is attracted to P1, C2 to P2, etc.
The boxes cannot overlap.
I made a diagram that may make it easier to understand:
The question is, what algorithm can I use to move the boxes around so that each Ci is the closest possible to its respective Pi. In other words, how do I find the locations for the Ci points that minimizes the distance (Li) between all Ci-Pi pairs?
I'd also be helpful if you can point me in to some material to read or something, I'm not very familiar with this type of problems... My guess is that some sort of force-directed algorithm would work but I'm not sure how to implement those.
Since "each box is attracted to one attractor point with a force proportional to the distance", you are describing a system where the boxes are attached to the attractor points by springs (see Hooke's law), and you want to determine the state of the system at rest (the state of minimum potential energy).
Because the forces are proportional to the distances, what you want is to minimize the sum of the distances squared, or the sum of Li^2 from i=0 to i=n. Here is an algorithm to do that.
The idea is to group boxes that need to touch by the end and figure out their position as a group based on their corresponding attractor points.
The first step is not to find these groups, because we can actually start with one big group and cut it later if necessary. For simplicity, let's treat all Li as signed distances. So Li = Ci-Pi. Let's also name the sizes of the boxes, though it will be easier to handle half-sizes. So let Si be half the size of the i-th box. Finally, let's write the sum of Xi from i=a to i=b like sum[a,b](Xi).
Here is how to compute the position of a group of boxes, assuming each one touches the next. Li is a function of the position of the group: if x is that position, Li(x) = Ci(x) - Pi (where Ci(x) is just x plus some constant). x can be point of the group of box, for example the left edge of the first box.
We also know that sum[a,b](Li(x)^2) must be minimal. This means the derivative of that sum must be zero: sum[a,b](2*Li(x)) = 0. So:
sum[a,b](2*Li) = 0
sum[a,b](Li) = 0
sum[a,b](Ci - Pi) = 0
sum[a,b](Ci) = sum[a,b](Pi)
Computing sum[a,b](Pi) is trivial, and sum[a,b](Ci) can be expressed in terms of Ca (center of the first box), since C[i+1] = Ci + Si + S[i+1].
Now that you can compute the position of a group of boxes, do it first with a group made of all boxes, and then remove boxes from that group as follows.
Starting from the left, consider all boxes with Li > 0 and compute Q = sum(Li) for all corresponding i. Similarly, starting from the right, consider all boxes with Li < 0 and compute R = -sum(Li) for all corresponding i (note that negative sign, because we want the absolute value). Now, if Q > R, remove the boxes on the left and make a new group with them, otherwise remove the boxes on the right and make a new group with them.
You cannot make these two new groups at the same time, because removing boxes from one end can change the position of the original group, where boxes you would have removed from the other end should not be removed.
If you made a new group, repeat: compute the position of each separate group of boxes (they will never overlap at this point), and remove boxes if necessary. Otherwise, you have your solution.
It seems the objective is a quadratic function and all the constraints are linear. So I think you can solve it by standard quadratic programming solvers.
If we write S_i be the half-size of i-th box, and the Pi's are given, then:
Minimize y
with respect to C_1, C_2, ...C_n
subject to
y = sum_i (P_i - C_i)^2
C_i + S_i + S_{i+1} <= C_{i+1} for each i = 1, ... n-1
Edit: this is a crude solution to minimize the sum of all Li, which is no longer the question.
Let's name the boxes B, so Bi has center Ci. Let n be the number of boxes and points.
Assuming all the boxes can fit into the larger range, here is how I would do it:
Let Q(a, b) be the average of Pi from i=a to i=b.
Place all the boxes next to each other (in order) to form a superbox, so that the center of this superbox is at Q(1, n).
If it goes over one end of the larger range, move it so that it sits at the limit.
Then, for each Bi, move it as close to Pi as possible without moving other boxes (and while still being inside the larger range). Repeat until you can't move any more box.
Now, the only way to minimize the sum of all Li is as follows.
Let G be a group of boxes that touch. Let F(G) be the predicate: if the center boxes of a series are Bi and Bj (if there are an odd number of boxes in the series, i=j), then Ci != Pi and Cj != Pj.
Find a G such that F(G) is true, and move the corresponding boxes so that F(G) becomes false. If the group of boxes hit another box while moving, add that box to the group and repeat. Of course, don't move any box outside the larger range.
Once there is no G for which F(G) is true or for which you would need to move outside the larger range, you have your solution (one of potentially an infinite number).
Just for completion, I found a (probably subtompimal) solution that works pretty well and is very easy to implement.
Place all boxes with their Ci's at their Pi's.
Go over all boxes, from left to right and do the following:
Check if box i overlaps with the box to its left. If it is the first box, check if it overlaps with the range minimum.
If there is overlap, move the box to the right so that there is no left overlap.
Repeat step 2 but from right to left, checking right overlaps (or range maximum for the last box).
Repeat steps 2-3 until no more overlaps remain or a maximum number of repetitions is reached.
It's quite efficient for my relatively small dataset and I get good results with 10 repetitions of steps 2-3 (5 left to right checks, 5 right to left checks).
I have an array of box objects, defined by their (x,y,width,height) properties like so:
Box Q is anchored at corner point C. How can I programatically expand box Q to take up all the available space it has, while maintaining its aspect ratio?
I have had some luck by expanding box to be very large (from the top right corner) and then aligning to the top edge of the furthest box (in this case 5). If at that point other boxes overlap with Q, I remove the furthest box (5) and repeat (align to the top edge of 4), until no boxes overlap. The problem with this approach is that a box may overlap with Q (box 2 in the next image), but when I scale to meet its top edge, it is no longer contained, like this:
Any thoughts on an approach would be much appreciated,
Josh
but when I scale to meet its top edge, it is no longer contained
Instead scale to meet its
top edge
bottom edge
left edge
right edge
Then, see which scaling is valid (the box is contained after scaling) and results in the biggest box.
I can see two approaches here.
First is to iterate over all other boxes. For each box B, see how much (by what factor) you can expand your given box Q so that it will touch box B; after that take the minimal of all such factors. However, finding this factor for a given B is a non-trivial task, though definitely solvable.
At the same time, if you already have a code that checks for overlaps for a given factor, then you can apply binary search to find the maximal factor that does not lead to overlap.
So you know that if you expand it a lot (say by x times), it does overlap. If you do not expand it (that is, expand by 1 times), it does not overlap. So you have a segment [1,x] where to search for an answer. Try the middle --- expand by (x+1)/2 times and see whether it overlaps. If it overlaps, continue with segment [1, (x+1)/2], otherwise with segment [(x+1)/2, x]. Take the middle of the new segment, and so on until the end values of your segment are close enough.
Create a function that will take in a scaling factor as a parameter, and have it return true or false depending on if there is overlap found or not. It seems like you already have something like this function written.
Then use bisection search https://en.wikipedia.org/wiki/Bisection_method to find your scaling factor to a threshold that is satisfactory.
I have a question about the box stacking algorithm that was suggested here:
http://people.csail.mit.edu/bdean/6.046/dp/
The algorithm making some wrong assumption:
In the video, it says that we "sort the boxes in order of decresing base area...etc".
We do it because 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.
but if box B_1 has a base area that is bigger the box B_2, that doesn't mean that it also has its width and depth bigger than the width and depth of box B_2.
for example, a box with a 1x8 base dimensions has a bigger base area than a box with a 2x3 dimensions, but still: 1<2 (and 1<3), and therefor we cannot stack box B_2 onto B_1.
what am I missing here?
It's a question of necessary versus sufficient conditions. It's true that you can run into situations where B_2 can't be stacked on B_1, but under those circumstances, B_1 couldn't be stacked on B_2 either, so there'd be no value in switching them in the consideration order. That is, if B_a has a larger base than B_b, we know that B_a cannot be stacked on B_b (because it has at least one dimension violating the constraint).
Put differently: In the optimal stack of boxes, all are ordered by decreasing base area. So if the list of all boxes is ordered by decreasing base area, the optimal stack is guaranteed to be a subsequence of the list of all boxes -- and so, of course, is the sequence consisting of only the first k boxes. Which means that, as required by dynamic programming, when examining box k, the optimal stack which box k can rest on has already been generated during a previous round.
It is confusing how this is presented but the whole point is to find a sequence from which you can apply the LIS (least increasing subsequence) on.
I have a fairly large set of 2D points (~20000) in a set, and for each point in the x-y plane want to determine which point from the set is closest. (Actually, the points are of different types, and I just want to know which type is closest. And the x-y plane is a bitmap, say 640x480.)
From this answer to the question "All k nearest neighbors in 2D, C++" I got the idea to make a grid. I created n*m C++ vectors and put the points in the vector, depending on which bin it falls into. The idea is that you only have to check the distance of the points in the bin, instead of all points. If there is no point in the bin, you continue with the adjacent bins in a spiralling manner.
Unfortunately, I only read Oli Charlesworth's comment afterwards:
Not just adjacent, unfortunately (consider that points in the cell two
to the east may be closer than points in the cell directly north-east,
for instance; this problem gets much worse in higher dimensions).
Also, what if the neighbouring cells happen to have less than 10
points in them? In practice, you will need to "spiral out".
Fortunately, I already had the spiraling code figured out (a nice C++ version here, and there are other versions in the same question). But I'm still left with the problem:
If I find a hit in a cell, there could be a closer hit in an adjacent cell (yellow is my probe, red is the wrong choice, green the actual closest point):
If I find a hit in an adjacent cell, there could be a hit in a cell 2 steps away, as Oli Charlesworth remarked:
But even worse, if I find a hit in a cell two steps away, there could still be a closer hit in a hit three steps away! That means I'd have to consider all cells with dx,dy= -3...3, or 49 cells!
Now, in practice this won't happen often, because I can choose my bin size so the cells are filled enough. Still, I'd like to have a correct result, without iterating over all points.
So how do I find out when to stop "spiralling" or searching? I heard there is an approach with multiple overlapping grids, but I didn't quite understand it. Is it possible to salvage this grid technique?
Since the dimensions of your bitmap are not large and you want to calculate the closest point for every (x,y), you can use dynamic programming.
Let V[i][j] be the distance from (i,j) to the closest point in the set, but considering only the points in the set that are in the "rectangle" [(1, 1), (i, j)].
Then V[i][j] = 0 if there is a point in (i, j), or V[i][j] = min(V[i'][j'] + dist((i, j), (i', j'))) where (i', j') is one of the three neighbours of (i,j):
i.e.
(i - 1, j)
(i, j - 1)
(i - 1, j - 1)
This gives you the minimum distance, but only for the "upper left" rectangle. We do the same for the "upper right", "lower left", and "lower right" orientations, and then take the minimum.
The complexity is O(size of the plane), which is optimal.
For you task usually a Point Quadtree is used, especially when the points are not evenly distributed.
To save main memory you als can use a PM or PMR-Quadtree which uses buckets.
You search in your cell and in worst case all quad cells surounding the cell.
You can also use a k-d tree.
A solution im trying
First make a grid such that you have an average of say 1 (more if you want larger scan) points per box.
Select the center box. Continue selecting neighbor boxes in a circular manner until you find at least one neighbor. At this point you can have 1 or 9 or so on boxes selected
Select one more layer of adjacent boxes
Now you have a fairly small list of points, usually not more than 10 which you can punch into the distance formula to find the nearest neighbor.
Since you have on average 1 points per box, you will mostly be selecting 9 boxes and comparing 9 distances. Can adjust grid size according to your dataset properties to achieve better results.
Also, if your data has a lot of variance, you can try 2 levels of grid (or even more) so if selection works and returns more than 50 points in a single query, start a next grid search with a grid 1/10th the size ...
One solution would be to construct multiple partitionings with different grid sizes.
Assume you create partitions at levels 1,2,4,8,..
Now, search for a point in grid size 1 (you are basically searching in 9 squares). If there is a point in the search area and if distance to that point is less than 1, stop. Otherwise move on to the next grid size.
The number of grids you need to construct is about twice as compared to creating just one level of partitioning.
Input: a set of rectangles within the area (0, 0) to (1600, 1200).
Output: a point which none of the rectangles contains.
What's an efficient algorithm for this? The only two I can currently think of are:
Create a 1600x1200 array of booleans. Iterate through the area of each rectangle, marking those bits as True. Iterate at the end and find a False bit. Problem is that it wastes memory and can be slow.
Iterate randomly through points. For each point, iterate through the rectangles and see if any of them contain the point. Return the first point that none of the rectangles contain. Problem is that it is really slow for densely populated problem instances.
Why am I doing this? It's not for homework or for a programming competition, although I think that a more complicated version of this question was asked at one (each rectangle had a 'color', and you had to output the color of a few points they gave you). I'm just trying to programmatically disable the second monitor on Windows, and I'm running into problems with a more sane approach. So my goal is to find an unoccupied spot on the desktop, then simulate a right-click, then simulate all the clicks necessary to disable it from the display properties window.
For each rectangle, create a list of runs along the horizontal direction. For example a rectangle of 100x50 will generate 50 runs of 100. Write these with their left-most X coordinate and Y coordinate to a list or map.
Sort the list, Y first then X.
Go through the list. Overlapping runs should be adjacent, so you can merge them.
When you find the first run that doesn't stretch across the whole screen, you're done.
I would allocate an image with my favorite graphics library, and let it do rectangle drawing.
You can try a low res version first (scale down a factor 8), that will work if there is at least a 15x15 area. If it fails, you can try a high res.
Use Windows HRGNs (Region in .net). They were kind of invented for this. But that's not language agnostic no.
Finally you can do rectangle subtraction. Only problem is that you can get up to 4 rectangles each time you subtract one rect from another. If there are lots of small ones, this can get out of hand.
P.S.: Consider optimizing for maximized windows. Then you can tell there are no pixels visible without hit testing.
Sort all X-coordinates (start and ends of rectangles), plus 0 & 1600, remove duplicates. Denote this Xi (0 <= i <= n).
Sort all Y-coordinates (start and ends of rectangles), plus 0 & 1200, remove duplicates. Denote this Yj (0 <= j <= m).
Make a n * m grid with the given Xi and Yj from the previous points, this should be much smaller than the original 1600x1200 one (unless you have a thousand rectangles, in which case this idea doesn't apply). Each point in this grid maps to a rectangle in the original 1600 x 1200 image.
Paint rectangles in this grid: find the coordinates of the rectangles in the sets from the first steps, paint in the grid. Each rectangle will be on the form (Xi1, Yj1, Xi2, Yj2), so you paint in the small grid all points (x, y) such that i1 <= x < i2 && j1 <= y < j2.
Find the first unpainted cell in the grid, take any point from it, the center for example.
Note: Rectangles are assumed to be on the form: (x1, y1, x2, y2), representing all points (x, y) such that x1 <= x < x2 && y1 <= y < y2.
Nore2: The sets of Xi & Yj may be stored in a sorted array or tree for O(log n) access. If the number of rectangles is big.
If you know the minimum x and y dimensions of the rectangles, you can use the first approach (a 2D array of booleans) using fewer pixels.
Take into account that 1600x1200 is less than 2M pixels. Is that really so much memory? If you use a bitvector, you only need 235k.
You first idea is not so bad... you should just change the representation of the data.
You may be interessed in a sparse array of booleans.
A language dependant solution is to use the Area (Java).
If I had to do this myself, I'd probably go for the 2d array of booleans (particularly downscaled as jdv suggests, or using accelerated graphics routines) or the random point approach.
If you really wanted to do a more clever approach, though, you can just consider rectangles. Start with a rectangle with corners (0,0),(1600,1200) = (lx,ly),(rx,ry) and "subtract" the first window (wx1,wy1)(wx2,wy2).
This can generate at most 4 new "still available" rectangles if it is completely contained within the original free rectangle: (eg, all 4 corners of the new window are contained within the old one) they are (lx,ly)-(rx,wy1), (lx,wy1)-(wx1,wy2), (wx2,wy1)-(rx,wy2), and (lx,wy2)-(rx,ry). If just a corner of the window overlaps (only 1 corner is inside the free rectangle), it breaks it into two new rectangles; if a side (2 corners) juts in it breaks it into 3; and if there's no overlap, nothing changes. (If they're all axes aligned, you can't have 3 corners inside).
So then keep looping through the windows, testing for intersection and sub-dividing rectangles, until you have a list (if any) of all remaining free space in terms of rectangles.
This is probably going to be slower than any of the graphics-library powered approaches above, but it'd be more fun to write :)
Keep a list of rectangles that represent uncovered space. Initialize it to the entire area.
For each of the given rectangles
For each rectangle in uncovered space
If they intersect, divide the uncovered space into smaller rectangles around the covering rectangle, and add the smaller rectangles (if any) to your list of uncovered ones.
If your list of uncovered space still has any entries, they contain all points not covered by the given rectangles.
This doesn't depend on the number of pixels in your area, so it will work for large (or infinite) resolution. Each new rectangle in the uncovered list will have corners at unique intersections of pairs of other rectangles, so there will be at most O(n^2) in the list, giving a total runtime of O(n^3). You can make it more efficient by keeping your list of uncovered rectangles an a better structure to check each covering rectangle against.
This is a simple solution with a 1600+1200 space complexity only, it is similar in concept to creating a 1600x1200 matrix but without using a whole matrix:
Start with two boolean arrays W[1600] and H[1200] set to true.
Then for each visible window rectangle with coordinate ranges w1..w2 and h1..h2, mark W[w1..w2] and H[h1..h2] to false.
To check if a point with coordinates (w, h) falls in an empty space just check that
(W[w] && H[h]) == true