可以将矩形堆叠成最方形的排列

时间:2008-12-04 08:53:48

标签: layout stack geometry

我的情况

  • 我有一个N矩形
  • 矩形都具有相同的形状(例如2英寸宽x 1英寸高) - 让我们将这个尺寸称为Sw和Sh的宽度和高度
  • 我想将这些矩形放在一个网格中,使得这些矩形完全位于顶部并且彼此相邻 - 就像您在电子表格中看到的那样
  • 我需要的是:给定N,Sw和Sh的行数(R)和列数(C)是多少可以将这些反应堆叠成最方形的排列
  • 据了解,R& C可以提供比所需更多的单元格(例如,如果N = 15,Sw = 1,Sh = 1则R = 4,C = 4,对于15个矩形产生16“槽” - 这没关系。
  • 如果Sw = Sh那么我的谦逊的数学技能就足够了 - 当它们的矩形具有不同的宽度和高度时 - 坦率地说,这超出了我的范围。

一些笔记

  • 是的,我已经阅读了这个问题:Stacking rectangles to take as little space as possible但没有任何帮助。它也不是同一个问题。那个问题是关于可能有不同大小的矩形,在这个问题中矩形具有相同的大小
  • 是的,我在wolfram.com等上搜索过,但没有运气
  • 我没有强大的数学背景,所以我对这个问题的表达方式本身可能会阻止我找到答案 - 我已经尝试了与平铺,解剖,分解有关的相关搜索,并且没有任何成功任

一些例子

the * indicates the edges of the rects
the | indicates that a cell is "filled-in"
Notice that not all R*C cells are filled in, but only and exactly N cells

IF N=1, Sw=2, Sh=1 THEN R=1, C=1

********
*||||||*
********

IF N=2, Sw=2, Sh=1 THEN R=2, C=1

********
*||||||*
********
*||||||*
********

IF N=3, Sw=2, Sh=1 THEN R=2, C=2


***************
*||||||*      *
***************
*||||||*||||||*
***************

IF N=4, Sw=2, Sh=1 THEN R=2, C=2


***************
*||||||*||||||*
***************
*||||||*||||||*
***************

IF N=5, Sw=2, Sh=1 THEN R=3, C=2


***************
*||||||*      *
***************
*||||||*||||||*
***************
*||||||*||||||*
***************

实施AaronofTomorrow的回答

# Implementation of AaronofTomorrow's answer
# implemented in python 2.6
# reasonable output
# works in constant time

import math

def f( N, Sw, Sh ) :
    cols = math.sqrt( float(N) * float(Sh) / float(Sw) )
    cols = round(cols)
    rows = float(N) / float(cols)
    rows = math.ceil(rows)
    return (int(cols),int(rows))

Will的答案启发的另一个实现(2008-12-08更新) - 这是我最终使用的那个

# Another implementation inspired by Will's answer
# implemented in python 2.6
# reasonable output - a bit better in yielding more squarelike grids
# works in time proportional to number of rects
#
# strategy used it to try incrementaly adding a rect.
# if the resulting rect requires more space then two
# possibilities are checked - adding a new row or adding a new col
# the one with the best aspect ratio (1:1) will be chosen 


def g( N, Sw, Sh ) :
    slope = float(Sh)/float(Sw)
    cols = 1
    rows = 1
    for i in xrange( N ) :
        num_to_fit =i+1
        allocated_cells= cols* rows
        if ( num_to_fit <= allocated_cells ) :
            pass # do nothing
        else :
            hc,wc = float(Sh * rows), float(Sw * (cols+1))
            hr,wr = float(Sh * (rows+1)), float(Sw * cols)
            thetac = math.atan( hc/wc)
            thetar = math.atan( hr/wr)
            alpha = math.pi/4.0
            difr = abs(alpha-thetar)
            difc = abs(alpha-thetac)
            if ( difr < difc ) :
                rows = rows +1
            else:
                cols = cols + 1

    return (cols,rows)

4 个答案:

答案 0 :(得分:2)

在Will Dean的回应的基础上,找到他的公式的衍生物(关于nCols):

-N * Sh / nCols + Sw

然后将其设置为0并求解nCols,得到:

nCols = sqrt(N * Sh / Sw)

回合那个,你应该有最佳的列数:

cols = round(sqrt(N * Sh / Sw))
   rows = ceil(N / cols)

答案 1 :(得分:1)

我认为你会发现'最像方形'是迈向“最像圆圈”的一步,这是圆周(周长)最小的点。

你的周长是2 * nRows * Sh + 2 * nCols Sw。你知道nRows nCols&gt; = N,我认为将它简化为nRows * nCols = N在下一位就可以了。

如果不尝试,我认为你可以尝试找到函数的最小值:

N/nCols*Sh + nCols*Sw

Dunno,如果其中任何一个可以工作,但它有助于我将工作日的开始延迟5分钟,所以这不是一个死亡。

答案 2 :(得分:0)

如果矩形的数量是无限的,你需要找到Sw和Sh的LCD(最小公分母)。然后你可以将它除以Sw和Sh来找到水平和垂直计数。

由于它是有限的,它是不同的。我是否正确理解您必须使用所有矩形,结果也必须是矩形?我会这么认为。

在这种情况下,您对如何排列矩形并没有太多选择。只有那么多整数对在乘法时给出N.

在你的情况下,我会尝试找到所有可能的这样的整数对(使用一个简单的FOR循环)并查看哪一个最接近正方形。在FOR循环通知中,您必须仅检查sqrt(N),因为在此之后找到的每个整数对将与您已找到的整数对相同,只是相反。

答案 3 :(得分:0)

首先,特殊情况下的正方形矩形或矩形,其中维度为零。

否则,为了简化说明,请迭代地构建它:

    add a new row until height is greater than width
    add a new column until width is greater than height

可能在代码中看起来像这样:

    // place the first tile as an initialisation
    int tiles = num_tiles - 1;
    int rows = 1;
    int columns = 1;
    int width = sx;
    int height = sy;

    int i=1; // just because we're curious how many iterations we have

    // build the near-square
    while(tiles > 0) {
        while((tiles > 0)
        && ((width + sx) <= (height + sy))) {
            // add a column
            tiles -= rows;
            columns++;
            width += sx;
        i++;
        }
        while((tiles > 0)
        && ((height + sy) < (width + sx))) {
            // add a row
            tiles -= columns;
            rows++;
            height += sy;
        i++;
        }
    }

    // done
    printf("%d = %d (%dx%d) = %dx%d (%dx%d) in %d\n",
    num_tiles,tiles,sx,sy,rows,columns,width,height,i);

和一些结果:

100 = -5 (10x20) = 7x15 (150x140) in 21
1000 = -12 (10x20) = 22x46 (460x440) in 67
10000000 = -1628 (10x20) = 2236x4473 (44730x44720) in 6708
200 = 0 (7x13) = 10x20 (140x130) in 29
2000 = -13 (7x13) = 33x61 (427x429) in 93
20000000 = -3790 (7x13) = 3282x6095 (42665x42666) in 9376
400 = -14 (17x13) = 23x18 (306x299) in 40
4000 = -15 (17x13) = 73x55 (935x949) in 127
40000000 = -192 (17x13) = 7232x5531 (94027x94016) in 12762

最坏情况O(n),非常非常薄的矩形或少量矩形。但O(sqrt(n))在一般情况下?