Rubí, 228 bytes * 21895 = 4992060
->n{a=(0..n*2).map{$b=' '*n}
g=0
m=n*2
(n**0.5).to_i.downto(1){|i|n%i<1&&(m=[m,n+h=n/i].min
g+=h+1
g<m+2?(a[g-h-1,1]=(1..h).map{?**i+$b}):(x=(m-h..m).map{|j|r=a[j].rindex(?*);r ?r:0}.max
(m-h+1..m).each{|j|a[j][x+2]=?**i}))}
a}
Varios cambios de código no golfizado. El más grande es el cambio de significado de la variable m
desde la altura del rectángulo más cuadrado, hasta la altura del rectángulo más cuadrado más n
.
Trivialmente, *40
se ha cambiado a lo *n
que significa una gran cantidad de espacios en blanco innecesarios a la derecha para grandes n
; y -2
se cambia a lo 0
que significa que los rectángulos trazados en la parte inferior siempre pierden las dos primeras columnas (esto da como resultado un embalaje más pobre para los números cuya única factorización es (n/2)*2
)
Explicación
Finalmente encontré tiempo para volver a esto.
Para un determinado, n
el campo más pequeño debe tener suficiente espacio para el rectángulo más largo 1*n
y el rectángulo más cuadrado x*y
. Debería ser evidente que el mejor diseño se puede lograr si ambos rectángulos tienen sus lados largos orientados en la misma dirección.
Ignorando el requisito de espacio en blanco entre los rectángulos, encontramos que el área total es (n+y)*x = (n+n/x)*x
o n*(x+1)
. De cualquier manera, esto se evalúa como n*x + n
. Incluyendo el espacio en blanco, tenemos que incluir un extra x
si colocamos los rectángulos de extremo a extremo, o n
si colocamos los rectángulos uno al lado del otro. Por lo tanto, lo primero es preferible.
Esto proporciona los siguientes límites inferiores (n+y+1)*x
para el área de campo:
n area
60 71*6=426
111 149*3=447
230 254*10=2540
400 421*20=8240
480 505*20=10100
Esto sugiere el siguiente algoritmo:
Find the value (n+y+1) which shall be the field height
Iterate from the squarest rectangle to the longest one
While there is space in the field height, draw each rectangle, one below the other, lined up on the left border.
When there is no more space in the field height, draw the remaining rectangles, one beside the other, along the bottom border, taking care not to overlap any of the rectangles above.
(Expand the field rightwards in the rare cases where this is necessary.)
En realidad, es posible obtener todos los rectángulos para los casos de prueba requeridos dentro de los límites inferiores mencionados anteriormente, con la excepción de 60, que proporciona el siguiente resultado de 71 * 8 = 568. Esto se puede mejorar ligeramente a 60 * 9 = 540 moviendo los dos rectángulos más delgados a la derecha un cuadrado y luego hacia arriba, pero el ahorro es mínimo, por lo que probablemente no valga ningún código adicional.
10
12
15
20
30
60
******
******
******
******
******
******
******
******
******
******
***** *
***** *
***** *
***** *
***** *
***** *
***** *
***** *
***** *
***** *
***** *
***** *
*
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
*
*** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
** *
** *
** *
** *
** *
** *
** *
** *
** *
** *
** *
Esto da un área total de 21895.
Código sin golf
f=->n{
a=(0..n*2).map{' '*40} #Fill an array with strings of 40 spaces
g=0 #Total height of all rectangles
m=n #Height of squarest rectangle (first guess is n)
(n**0.5).to_i.downto(1){|i|n%i<1&&(puts n/i #iterate through widths. Valid ones have n%i=0. Puts outputs heights for debugging.
m=[m,h=n/i].min #Calculate height of rectangle. On first calculation, m will be set to height of squarest rectangle.
g+=h+1 #Increment g
g<n+m+2? #if the rectangle will fit beneath the last one, against the left margin
(a[g-h-1,1]=(1..h).map{'*'*i+' '*40}) #fill the region of the array with stars
: #else
(x=(n+m-h..n+m).map{|j|r=a[j].rindex('* ');r ?r:-2}.max #find the first clear column
(n+m-h+1..n+m).each{|j|a[j][x+2]='*'*i} #and plot the rectangle along the bottom margin
)
)}
a} #return the array
puts f[gets.to_i]