Ruby, 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}
Mehrere Änderungen gegenüber ungolfed Code. m
Am größten ist die Änderung der Bedeutung der Variablen von der Höhe des quadratischsten Rechtecks zur Höhe des quadratischsten Rechtecks plus n
.
Trivial *40
wurde geändert, *n
was eine Menge unnötiger Leerzeichen rechts für große bedeutet n
; und -2
wird geändert, 0
was bedeutet, dass Rechtecke, die über den Boden gezeichnet sind, immer die ersten beiden Spalten verfehlen (dies führt zu einer schlechteren Packung für Zahlen, deren einzige Faktorisierung darin besteht (n/2)*2
).
Erläuterung
Ich fand endlich Zeit, darauf zurückzukommen.
Für ein bestimmtes n
Feld muss genügend Platz für das längste 1*n
und das quadratischste Rechteck vorhanden sein x*y
. Es sollte offensichtlich sein, dass das beste Layout erzielt werden kann, wenn beide Rechtecke ihre langen Seiten in die gleiche Richtung ausrichten.
Wenn wir die Anforderung von Leerzeichen zwischen den Rechtecken ignorieren, stellen wir fest, dass die Gesamtfläche entweder (n+y)*x = (n+n/x)*x
oder ist n*(x+1)
. In jedem Fall wird dies ausgewertet n*x + n
. Einschließlich des Leerzeichens müssen wir ein zusätzliches einfügen, x
wenn wir die Rechtecke Ende an Ende platzieren oder n
wenn wir die Rechtecke nebeneinander platzieren. Ersteres ist daher vorzuziehen.
Dies ergibt die folgenden Untergrenzen (n+y+1)*x
für den Feldbereich:
n area
60 71*6=426
111 149*3=447
230 254*10=2540
400 421*20=8240
480 505*20=10100
Dies legt den folgenden Algorithmus nahe:
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.)
Es ist tatsächlich möglich, alle Rechtecke für die erforderlichen Testfälle innerhalb der oben genannten unteren Grenzen zu erhalten, mit Ausnahme von 60, was die folgende Ausgabe von 71 * 8 = 568 ergibt. Dies kann leicht auf 60 * 9 = 540 verbessert werden, indem die beiden dünnsten Rechtecke um ein Quadrat nach rechts und dann nach oben verschoben werden. Die Einsparung ist jedoch minimal, sodass es wahrscheinlich keinen zusätzlichen Code wert ist.
10
12
15
20
30
60
******
******
******
******
******
******
******
******
******
******
***** *
***** *
***** *
***** *
***** *
***** *
***** *
***** *
***** *
***** *
***** *
***** *
*
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
**** *
*
*** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
** *
** *
** *
** *
** *
** *
** *
** *
** *
** *
** *
Dies ergibt eine Gesamtfläche von 21895.
Ungolfed Code
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]