适合该领域的因素


11

给定小于1000的正整数,则显示该区域内所有可能的矩形。

任务

假设输入为20。我们可以制作一个20×1、10×2或5×4的矩形,因此这是一个有效的输出:

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

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

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

请注意,每个可能的矩形仅出现一次。

矩形可以以任何顺序,方向或位置出现,但即使在角落,也不能有两个矩形重叠或接触。以下内容也有效:

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

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

计分

输出的边界框区域(BBA)是包围所有矩形的最小矩形的区域。在第一个示例输出中,大小为20×9,因此BBA为180。在第二个示例输出中,大小为20×7,因此BBA仅140。

输入为60、111、230、400和480时,找到输出的BBA,并将它们加起来。将该总和乘以代码的大小(以字节为单位)。结果就是你的分数;最低分获胜。

规则

  • 程序(或函数)必须为1000以下的任何正整数产生有效的输出。
  • 输出必须仅包含星号(*),空格()和换行符。
  • 矩形之间可以有任意数量的空间,但这要计入BBA。
  • 前导或尾随的行或列,如果仅有空格,则不会计入BBA。

特殊情况可以硬编码吗?
加尔文的爱好2015年

@ Calvin'sHobbies是的,但我怀疑这会有所帮助。
Ypnypn

3
@ Calvin'sHobbies大众解决方案。
级圣河

Answers:


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)*xn*(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

Ruby,56个字节

90385 * 56 = 5061560假设输出与Martin的输出相同(我相信是这样)。

->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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.