Встановити фактори в поле


11

За умови додатного цілого числа нижче 1000, відобразіть усі можливі прямокутники з цією областю.

Завдання

Скажімо, вхід дорівнює 20. Ми можемо зробити прямокутник 20 × 1, 10 × 2 або 5 × 4, тож це дійсний вихід:

********************

**********
**********

*****
*****
*****
*****

Зауважте, що кожен можливий прямокутник з’являється рівно один раз.

Прямокутники можуть з’являтися в будь-якому порядку, орієнтації чи положенні, але жоден два прямокутники не можуть перетинатися або торкатися навіть у кутах. Також діє:

********************

            ****
**********  ****
**********  ****
            ****
            ****

Оцінка балів

Площа обмежувального поля (BBA) виводу - це область мінімального прямокутника, що охоплює всі прямокутники. У першому прикладі виводу розмір становить 20 × 9, тому BBA - 180. У другому прикладі виводу розмір - 20 × 7, тож BBA - всього 140.

Знайдіть BBA виходу, коли вхід становить 60, 111, 230, 400 та 480, і додайте їх. Помножте цю суму на розмір коду в байтах. Результат - ваш рахунок; виграє найнижчий бал.

Правила

  • Програма (або функція) повинна дати дійсний вихід для будь-якого натурального числа, що не перевищує 1000.
  • Вихід повинен містити просто зірочки ( *), пробіли ( ) та нові рядки.
  • Між прямокутниками може бути пробіл, але це враховується як BBA.
  • Провідні або кінцеві лінії або стовпці, якщо вони мають просто пробіли, не враховуються до BBA.

Чи можна зашифрувати особливі випадки?
Захоплення Кальвіна

@ Calvin'sHobbies Так, але я сумніваюся, що це дуже допоможе.
Ypnypn

3
@ Calvin'sHobbies Рішення Volkswagen.
Рівень р. Св.

Відповіді:


3

Ruby, 228 байт * 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}

Кілька змін від коду, який не має волі. Найбільший - зміна значення змінної mвід висоти прямокутника прямокутника до висоти прямокутника прямокутника плюс n.

Тривіально, *40було змінено, *nщо означає багато непотрібних пробілів праворуч для великих n; і -2змінюється, 0що означає, що прямокутники, нанесені на дно, завжди пропускають перші два стовпці (це призводить до біднішої упаковки для чисел, єдиною факторизацією яких є (n/2)*2)

Пояснення

Нарешті я знайшов час повернутися до цього.

Для даного nнайменшого поля повинно бути достатньо місця як для найдовшого прямокутника, так 1*nі для прямокутника прямокутника x*y. Має бути очевидним, що найкращого компонування можна досягти, якщо обидва прямокутники мають довгі сторони, орієнтовані в одному напрямку.

Ігноруючи вимогу пробілу між прямокутниками, ми виявляємо, що загальна площа дорівнює (n+y)*x = (n+n/x)*xабо n*(x+1). Так чи інакше, це оцінюється n*x + n. Включаючи пробіли, ми повинні включити додатковий, xякщо розмістити прямокутники в кінці або nякщо розмістити прямокутники поруч. Тому перший є кращим.

Це дає наступні нижні (n+y+1)*xмежі для області поля:

n     area
60    71*6=426
111  149*3=447
230  254*10=2540
400  421*20=8240
480  505*20=10100

Це говорить про наступний алгоритм:

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.)

Фактично можливо отримати всі прямокутники для необхідних тестових випадків у вищезгаданих нижніх межах, за винятком 60, що дає наступний результат 71 * 8 = 568. Це можна трохи покращити до 60 * 9 = 540, перемістивши два найтонші прямокутники вправо на один квадрат, а потім вгору, але економія мінімальна, тому, мабуть, не варто зайвий код.

10
12
15
20
30
60
******
******
******
******
******
******
******
******
******
******

*****  *
*****  *
*****  *
*****  *
*****  *
*****  *
*****  *
*****  *
*****  *
*****  *
*****  *
*****  *
       *
****   *
****   *
****   *
****   *
****   *
****   *
****   *
****   *
****   *
****   *
****   *
****   *
****   *
****   *
****   *
       *
***    *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
*** ** *
    ** *
    ** *
    ** *
    ** *
    ** *
    ** *
    ** *
    ** *
    ** *
    ** *
    ** *

Це дає загальну площу 21895.

Невикористаний код

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]


1

Рубін, 56 байт

90385 * 56 = 5061560 припускаючи, що вихід такий самий, як і у Мартіна (я вважаю, це так).

->n{1.upto(n){|i|i*i<=n&&n%i==0&&puts([?**(n/i)]*i,'')}}

Ось ще одна корисна функція, в корисній програмі тестування

f=->n{1.upto(n){|i|i*i<=n&&n%i==0&&print(n/i,"*",i,"\n")};puts}

f[60];f[111];f[230];f[400];f[480]

Що дає наступний вихід, для довідки:

60*1
30*2
20*3
15*4
12*5
10*6

111*1
37*3

230*1
115*2
46*5
23*10

400*1
200*2
100*4
80*5
50*8
40*10
25*16
20*20

480*1
240*2
160*3
120*4
96*5
80*6
60*8
48*10
40*12
32*15
30*16
24*20
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.