Rubino, 228 byte * 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}
Diverse modifiche rispetto al codice non salvato. Il più grande è il cambiamento di significato della variabile mdall'altezza del rettangolo di squarest, all'altezza del rettangolo di squarest plus n.
In sostanza, *40è stato modificato con il *nsignificato di un sacco di spazi bianchi non necessari a destra per grandi n; e -2viene modificato, il 0che significa che i rettangoli tracciati nella parte inferiore mancano sempre delle prime due colonne (ciò si traduce in un impaccamento più scarso per i numeri la cui unica fattorizzazione è (n/2)*2)
Spiegazione
Ho finalmente trovato il tempo di tornare a questo.
Per un dato momento nil campo più piccolo deve avere abbastanza spazio sia per il rettangolo più lungo 1*nche per il rettangolo squarest x*y. Dovrebbe essere evidente che il layout migliore può essere ottenuto se entrambi i rettangoli hanno i lati lunghi orientati nella stessa direzione.
Ignorando il requisito per gli spazi bianchi tra i rettangoli, troviamo che l'area totale è o (n+y)*x = (n+n/x)*xo n*(x+1). Ad ogni modo, questo valuta n*x + n. Compreso lo spazio bianco, dobbiamo includere un extra xse posizioniamo i rettangoli da un capo all'altro o nse posizioniamo i rettangoli uno accanto all'altro. Il primo è quindi preferibile.
Ciò fornisce i seguenti limiti inferiori (n+y+1)*xper l'area del campo:
n area
60 71*6=426
111 149*3=447
230 254*10=2540
400 421*20=8240
480 505*20=10100
Questo suggerisce il seguente 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.)
In realtà è possibile ottenere tutti i rettangoli per i casi di test richiesti entro i limiti inferiori sopra menzionati, ad eccezione di 60, che fornisce il seguente 71 * 8 = 568 output. Questo può essere leggermente migliorato a 60 * 9 = 540 spostando i due rettangoli più sottili a destra di un quadrato e poi in alto, ma il risparmio è minimo, quindi probabilmente non vale alcun codice aggiuntivo.
10
12
15
20
30
60
******
******
******
******
******
******
******
******
******
******
***** *
***** *
***** *
***** *
***** *
***** *
***** *
***** *
***** *
***** *
***** *
***** *
*
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
*
*** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
** *
** *
** *
** *
** *
** *
** *
** *
** *
** *
** *
Questo dà una superficie totale di 21895.
Codice Ungolfed
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]