Vamos W
y H
sea la anchura y la altura del rectángulo.
Let s
sea la longitud del lado de un cuadrado.
A continuación, el número de plazas n(s)
que puede encajar en el rectángulo es floor(W/s)*floor(H/s)
. Desea encontrar el valor máximo de s
para el cual n(s) >= N
Si traza el número de cuadrados contra s
, obtendrá una función por partes constante. Las discontinuidades están en los valores W/i
y H/j
, donde i
y j
pasan por los enteros positivos.
piensa que no hay la más pequeña i
para los que n(W/i) >= N
, y del mismo modo el más pequeño para el que j
n(H/j) >= N
. Llame a estos valores más pequeños i_min
y j_min
. Entonces, el más grande de W/i_min
y H/j_min
es el s
que desea.
I.e.s_max = max(W/i_min,H/j_min)
Para encontrar i_min
y j_min
, acaba de hacer una búsqueda de fuerza bruta: para cada uno, empezar desde 1, prueba, y el incremento.
En el caso de que N sea muy grande, puede ser desagradable buscar i
y j
a partir de 1 (aunque es difícil imaginar que haya una diferencia notable en el rendimiento). En este caso, podemos estimar los valores iniciales de la siguiente manera. Primero, una estimación aproximada del área de una loseta es W*H/N
, correspondiente a un lado de sqrt(W*H/N)
. Si W/i <= sqrt(W*H/N)
, entonces i >= ceil(W*sqrt(N/(W*H)))
, de manera similar j >= ceil(H*sqrt(N/(W*H)))
Así, en lugar de iniciar los lazos en i=1
y j=1
, podemos empezar a ellos en i = ceil(sqrt(N*W/H))
y j = ceil(sqrt(N*H/W)))
. Y OP sugiere que round
funciona mejor que ceil
- en el peor de los casos, una iteración extra.
Aquí es el algoritmo explicado en 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) ;
}
Lo anterior está escrito para mayor claridad. El código se puede ajustar considerablemente de la siguiente manera:
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) ;
}
¿Tiene un tamaño fijo para la caja de herramientas en las direcciones horizontal y vertical? ¿Tiene un tamaño mínimo y/o máximo para los botones? – ebynum
@ebynum Sí, tanto X como Y están predefinidos. Y sí, hay un tamaño máximo para los botones, pero si se encuentra que el tamaño óptimo es mayor que el máximo, podría usar el máximo en su lugar (por lo que realmente no cambia el problema de la IMO). –
me gustaría señalar que esto tiene una enorme aplicación comercial si se aplica a formas poligonales no rectangulares. los productos que "anidan" formas para obtener la máxima densidad de producto siempre están en demanda para la industria manufacturera. –