Let W
and H
be the width and height of the rectangle.
Let s
be the length of the side of a square.
Then the number of squares n(s)
that you can fit into the rectangle is floor(W/s)*floor(H/s)
. You want to find the maximum value of s
for which n(s) >= N
If you plot the number of squares against s
you will get a piecewise constant function. The discontinuities are at the values W/i
and H/j
, where i
and j
run through the positive integers.
You want to find the smallest i
for which n(W/i) >= N
, and similarly the smallest j
for which n(H/j) >= N
. Call these smallest values i_min
and j_min
. Then the largest of W/i_min
and H/j_min
is the s
that you want.
I.e. s_max = max(W/i_min,H/j_min)
To find i_min
and j_min
, just do a brute force search: for each, start from 1, test, and increment.
In the event that N is very large, it may be distasteful to search the i
's and j
's starting from 1 (although it is hard to imagine that there will be any noticeable difference in performance). In this case, we can estimate the starting values as follows. First, a ballpark estimate of the area of a tile is W*H/N
, corresponding to a side of sqrt(W*H/N)
. If W/i <= sqrt(W*H/N)
, then i >= ceil(W*sqrt(N/(W*H)))
, similarly j >= ceil(H*sqrt(N/(W*H)))
So, rather than start the loops at i=1
and j=1
, we can start them at i = ceil(sqrt(N*W/H))
and j = ceil(sqrt(N*H/W)))
. And OP suggests that round
works better than ceil
-- at worst an extra iteration.
Here's the algorithm spelled out in C++:
#include <math.h>
#include <algorithm>
// find optimal (largest) tile size for which
// at least N tiles fit in WxH rectangle
double optimal_size (double W, double H, int N)
{
int i_min, j_min ; // minimum values for which you get at least N tiles
for (int i=round(sqrt(N*W/H)) ; ; i++) {
if (i*floor(H*i/W) >= N) {
i_min = i ;
break ;
}
}
for (int j=round(sqrt(N*H/W)) ; ; j++) {
if (floor(W*j/H)*j >= N) {
j_min = j ;
break ;
}
}
return std::max (W/i_min, H/j_min) ;
}
The above is written for clarity. The code can be tightened up considerably as follows:
double optimal_size (double W, double H, int N)
{
int i,j ;
for (i = round(sqrt(N*W/H)) ; i*floor(H*i/W) < N ; i++){}
for (j = round(sqrt(N*H/W)) ; floor(W*j/H)*j < N ; j++){}
return std::max (W/i, H/j) ;
}