设W 和H 为矩形的宽度和高度。
设s 为正方形的边长。
那么你可以放入矩形的正方形n(s)的数量是floor(W/s)*floor(H/s)。你想找到s的最大值,n(s) >= N
如果您根据s 绘制平方数,您将得到一个分段常数函数。不连续点位于值W/i 和H/j,其中i 和j 贯穿正整数。
您想找到最小的i 对应的n(W/i) >= N,以及类似的最小的j 对应的n(H/j) >= N。将这些最小值称为i_min 和j_min。那么W/i_min 和H/j_min 中最大的就是你想要的s。
即s_max = max(W/i_min,H/j_min)
要查找i_min 和j_min,只需进行蛮力搜索:对于每个,从 1 开始,测试并递增。
如果N非常大,从1开始搜索i和j可能会令人反感(尽管很难想象性能会有任何明显的差异) .在这种情况下,我们可以如下估计起始值。首先,瓷砖面积的大致估计是W*H/N,对应于sqrt(W*H/N)的一侧。如果W/i <= sqrt(W*H/N),那么i >= ceil(W*sqrt(N/(W*H))),类似j >= ceil(H*sqrt(N/(W*H)))
因此,我们可以从i = ceil(sqrt(N*W/H)) 和j = ceil(sqrt(N*H/W))) 开始,而不是在i=1 和j=1 开始循环。并且 OP 建议 round 比 ceil 工作得更好——最坏的情况是额外的迭代。
以下是用 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) ;
}
上面是为了清楚起见而写的。代码可以大大收紧如下:
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) ;
}