Fitting equal rectangles into larger rectangle - algorithm

I have a single large rectangle of dimensions L*W, and n smaller rectangles that each have the same dimension l * w. Every small rectangle has the same dimensions.
My goal is to fit all n of smaller rectangles into the large rectangle while making the most efficient use of space in the large rectangle possible. l and w can be scaled up or down as needed, as long as the proportion is kept the same.
How can it be determined how the smaller rectangles should be scaled to fit them all in the large rectangle?

Here is an algorithm that finds the max value of a scaling factor F such that all small a x b rectangles, when scaling by F will fit in the containing rectangle A x B:
For every pair (p, q) of positive integers such that
p <= n
q <= n
n = p * q - r for some integer r >= 0 satisfying r < p or p < q
compute f = min(A/(a*p), B/(b*q)).
Let F be the maximum of all factors f computed in 1.
The computation of all pairs (p, q) may proceed as follows:
[Initialize] p := 0
[Increment] p := p + 1
[End?] If p > n, stop
[Next] Let q := n + p - 1 / p (integer division). Next pair (p, q).
[Repeat] Go to 2.
Idea of the algorithm
Every pair (p, q) represents a particular layout of the scaled rectangles with p rectangles in an horizontal row and q rows, the last one possibly incomplete. Here is an example for n = 13 written as 3 * 5 - 2:
Since p scaled rectangles of width f*a must fit in a rectangle of width A, we have: p*f*a <= A or f <= A/(p*a). Similarly f <= B/(q*b). Therefore the maximum scale for this configuration is min(A/(p*a), B/(q*b)).

Related

Algorithm for optimizing grid of elements by a similarity function?

Suppose you have an N x N matrix of element type T.
Let's say the eight neighbours of a given element E are the other cells in the 3x3 square with E at its center:
.......
.......
...XXX.
...XEX.
...XXX.
.......
X = neighbour
There is a commutative binary function f(a,b) on pairs of T that returns a float between 0.0 and 1.0. (f(a,b) = f(b,a) and f(a,a) = 0 for all a, b in T.)
We want to rearrange the elements of the matrix to minimize the total of f between neighbouring cells.
That is, we want to minimize totalf:
totalf = 0
for x in 1 to N
for y in 1 to N
for dx in -1 to +1
for dy in -1 to +1
totalf += f(M[x,y], M[x+dx,y+dy])
Any ideas? Is there a standard problem this is similar to?

Maximum area rectangle

Given set of points (x[1]; y[1]), (x[2]; y[2]), ..., (x[n]; y[n]) . We need to find maximum area of rectangle that we can get. Rectangle's vertexes should be in points set. Also, rectangle is not necessary be axis-aligned. For example, answer for (1; 1), (2; 2), (2; 0); (3; 1) is 2.
n <= 1300; -10^9 <= x[i], y[i] <= 10^9.
Can someone help me with this problem? My solution is brute-force O(N^3), it's giving TLE. I select some three points and find fourth.
Every pair of points determines a line L, which has a slope m and an intercept c. (Ignore vertical lines for now.) Instead of considering the intercept, let's work with a different quantity that gives much the same information: The distance d(L) between the line and the origin, i.e., the length of a line segment R perpendicular to L and connecting L to the origin. Additionally, we can talk about the "displacement" of a point along L: We can say that the point p on L where it meets R has displacement 0, and the point on L that is x "above" p (has distance x from p and higher y coordinate) has displacement x, with negative displacements for points "below" p. In fact, we don't need the intercept or d(L) to define the displacement of a point with respect to a line L -- just the line's slope. Define disp(m, q) to be the displacement of point q on a line with slope m.
Suppose a, b, c, d are the vertices of a rectangle, with sides ab, bc, cd and da. Observe that the line containing ab has the same slope m as the line containing cd, and (disp(m, a), disp(m, b)) = (disp(m, d), disp(m, c)). So the only 4-tuples of vertices that we need to test are those comprised of pairs of vertex pairs like ab and cd -- vertex pairs having the same slope and displacement pairs. Furthermore, one side length (shared by ab and cd) is equal to |disp(m, b) - disp(m, a)|, and the other side length will be |d(Lab) - d(Lcd)|, where Lab and Lcd are the lines containing the line segments ab and cd, respectively.
To find these 4-tuples of vertices efficiently:
For all pairs of vertices i, j:
Let L be the line passing through i and j. Compute its slope m and distance d(L) from the origin. Also compute disp(m, i) and disp(m, j). If disp(m, i) <= disp(m, j), add the tuple (m, disp(m, i), disp(m, j), d(L)) to an array Z.
Sort Z lexicographically. This will place all point pairs lying on lines of the same slope and having equal displacements in a contiguous block, ordered by increasing d(L).
Scan through the array, looking for block boundaries -- positions k at which any of the first three tuple elements changes. Let prev be the last such k found (initially, prev = 0). For each such k:
Compute (Z[k-1][3] - Z[prev][3]) * (Z[k-1][2] - Z[k-1][1]). This is the area of the largest rectangle having a pair of sides with slope Z[k-1][0] and length (Z[k-1][2] - Z[k-1][1]). If this is greater than the maximum rectangle size found so far, update it.
This algorithm takes O(n^2 log n) time and O(n^2) space.

Find all points on a line that intersect perfectly with a grid?

I am trying to solve this math concept programmatically. Given two points A and B, on a rounded grid, find the points along the line from A to B that intersect with the rounded grid. I have looked into fast voxel traversal algorithms but they do not seem to only get points that are on the grid, instead just any points that intersect.
Here is a picture that might better describe my problem:
I am given the two orange points on any line, but I want to be able to find the blue points that that line intersects with. As you can see, the blue points are rounded to the grid.
Let me know if I can clarify anything.
There's two points that we know will always be aligned with the grid: the points at the end of the segment. I'll call them a and b. The vector describing the segment is then b - a (v).
v can be reduced while maintaining the ratio of the vector as follows:
v' = v / gcd(v_x, v_y)
where v_x and v_y are the x and y-components of v respectively. v' is the smallest possible vector with the same orientation as v consisting solely of integer components. This means that a + v' * n will be aligned to the grid for any n we may pick.
So the points on the line that are grid-aligned would be [a + 0 * v', a + 1 * v', ..., a + m * v'], where a + m * v' = b must hold. So we need to solve
a_x + m * v'_x = b_x
a_y + m * v'_y = b_y
which lead to
m = (b_x - a_x) / v'_x
m = (b_y - a_y) / v'_y
However there are three possible edge-cases to consider here:
a == b: none of the equations are solveable (and there's exactly one grid-aligned point anyways)
v'_x == 0 or v'_y == 0: just pick the other equation to find m
Putting it all together as pythonesque pseudocode:
grid_aligned(a, b):
if a == b:
return [a]
v = b - a
v' = v / gcd(v.x, v.y)
if v'.x == 0:
m = v.y / v'.y
else:
m = v.x / v'.x
return [a + v' * n for n in 0..m]

get a specific combination with replacement

I know how to calculate the total number of combinations of n different objects taken k at a time, with replacement:
(n+k-1)!/k!/(n-1)!
What I need is a formula or algorithm to recover the i-th such combination from an ordered list.
Say I have an ordered list of all combinations of a,b,c taken 3 at a time (so n=3 and k=3):
1 aaa
2 aab
3 aac
4 abb
5 abc
6 acc
7 bbb
8 bbc
9 bcc
10 ccc
How would I calculate the i-th (say 7-th) combination in this list, without first enumerating them all ? Enumerating will be very inefficient for any but the simplest cases, if I am only interested in a few specific combinations. For instance, there are 119,877,472 combinations of 64 items taken 6 at a time.
Needless to say, I need a solution for arbitrary n, k and i.
The reverse function (given the combination, how to calculate its index) would also be interesting.
I found one similar question, but it was about permutations, not combinations:
I want to get a specific combination of permutation?
And there are many ways to list all the combinations, such as mentioned here:
How to generate all permutations and combinations with/without replacement for distinct items and non distinct items (multisets)
But they don't give the functions I need
The algorithm you are interested in is very easy to implement. The first thing you should understand is why actually C(k, n + k - 1) = C(n - 1, n + k - 1) = (n + k - 1)! / k! / (n - 1)! formula works. Formula says that the number of ways to take k items out of n is the same as to take n-k items out of n.
Lets say your objects are balls of some color. There are n different colors numbered from 1 to n. You need to calculate the number of ways to have k balls. Imagine initially k white balls (without any color) so you need to paint them in different ways. Arrange the balls in a row. Choose some k1 ≥ 0 balls from the left to paint in color #1, next k2 ≥ 0 balls we paint in #2, and so on... We have ∑ki = k. A series of k1 balls painted in color #1 is followed by k2 of color #2, next by k3 of color #3 etc...
We can do the same painting in a slightly different way however. In order to separate ki-1- and ki-colored balls we would use delimiters. In total we should have n - 1 such delimiters to be placed among the balls. The delimiters are ordered, one that separates 1-colored and 2-colored balls should appear before another that separates 2-colored and 3-colored. If some ki = 0 then corresponding delimiters appear one by one. We have to arrange delimiters and balls in some way.
Interestingly we can imagine now that both n - 1 delimiters and k balls are just objects initially placed in a row. We have to choose either n - 1 of them to declare selected objects to be delimiters or k objects to be balls. And that's where well-known combination formula can be applied.
Example for your case:
o - ball
. - delimiter
a, b, c - colors
We have:
ooo.. => aaa
oo.o. => aab
oo..o => aac
o.oo. => abb
o.o.o => abc
o..oo => acc
.ooo. => bbb
.oo.o => bbc
.o.oo => bcc
..ooo => ccc
Notice the pattern how delimiters move from right to left.
Algorithm
Now to the question of how to get the p-th arrangement. Efficient algorithm description follows. Remember that we have k balls and nd = n - 1 delimiters. We will be placing delimiters one by one first trying their rightmost positions. Consider leaving current delimiter at its current position, calculate the number of combinations to place the remaining objects to the right, let the number be some N. Compare N with p, if p is greater or equal to N then reduce p by N (p <- p - N) and we should move current delimiter left by 1. Else if p is lower than N then we will not move current delimiter but proceed to the next one trying to move it again from the rightmost position. Note that p-th arrangement is zero-based.
Having "converted" some i-th object to j-th delimiter we have N = C(nd - j, nd + k - i) number of ways to arrange remaining k - i + j balls and nd - j delimiters.
Since we'll often refer to binomial coefficients we'd better make their precalculation.
The reverse function may be implemented accordingly. You have positions for every delimiter. Accumulate the number of ways to arrange remaining objects while moving ordinary delimiter to its place from the rightmost position.
Example:
3 balls, 2 delimiters, find 7-th arrangement (which is bbc or .oo.o)
Place delimiters to the rightmost position: ooo... Let first delimiter be current.
Calculate N = C(1, 1) = 1, p ≥ N so we reduce p by N getting p = 6. At the same time we move current delimiter 1 pos left getting oo.o..
Calculate N = C(1, 2) = 2, p ≥ N, reduce p by N getting p = 6 - 2 = 4. Move getting o.oo..
Calculate N = C(1, 3) = 3, p ≥ N once again, move and reduce p getting p = 1 and .ooo..
Calculate N = C(1,4) = 4, p < N. Good, we've found final position for the first delimiter so leave it there and take second delimiter as current.
Calculate N = C(0,0) = 1, p ≥ N, p = 1 - 1 = 0, move, .oo.o.
Calculate N = C(0,1) = 1, p < N, found final position for the second delimiter. Resulting arrangement is .oo.o => bbc.
EDIT #1. Changed the algo description and added example.
here is the function (not optimized but working):
findcomb <- function(n, k, p) {
# n = nr of object types (colors, letters etc)
# k = number of objects (balls) to select
# p = 0-based index of target combination
# return = positions of delimiters at index p
nd <- n-1 #nr of delimiters: 1 - nr of colors
pos <- seq(n+k-nd, n+k-1) #original positions of delimiters, all at right
for (j in 1:(nd-1)) {
s <- 0 #cumulative nr of accounted-for combinations with this delimiter
while (TRUE) {
N <- choose(nd+k-pos[j], nd-j)
if (s + N <= p) {
pos[j] <- pos[j] - 1
s <- s + N
} else break
}
p <- p - s
}
#last delimiter:
pos[nd] <- pos[nd] - p
pos
}

Optimizing a 2 parameter distance function on line segments (ACM ICPC Regionals Elim.)

This problem is a subproblem of a problem posed in the ACM ICPC Kanpur Regionals Elimination Round:
Given 2 line segments bounded by the 2D points (Pa, Pb) and (Pc, Pd) respectively, find p and q (in the range [0,1]) that minimizes the function
f(p, q) = D(Px, Pa) + D(Py, Pd) + k D(Px, Py) where
2 <= k <= 5,
Px = p Pa + (1-p) Pb,
Py = q Pc + (1-q) Pd and
D(x, y) is the euclidean distance between points x and y
(effectively, Px and Py are points on the line segments and the function encodes the cost of going from Pa to Pd through a connecting link of a cost that is k times the euclidean distance)
Some observations regarding this function:
Parallel line segments will always cause atleast one of p and q to be either 0 or 1
Intersecting line segments will always cause p and q to locate the point of intersection of the line segments (the triangle inequality can be applied to prove this)
The question:
In the general case where the lines are inclined and potentially separated, how do we minimize this function?
I think you should be able to take the partial derivatives of f with respect to p and q, set them to 0, and solve for p and q. That will give you a (local) minimum. If the minimum has 0 <= p <= 1 and 0 <= q <= 1, you're done, otherwise check the four endpoints (p=0,q=1, and so on).
I'm not positive that this will handle all degenerate conditions, but it should be a good start.

Resources