Algorithm 平铺算法

Algorithm 平铺算法,algorithm,math,block,tile,Algorithm,Math,Block,Tile,我有一块36 x 36英寸宽和高的瓷砖 所以我有8x8,6x6,6x8,4x8块,它们可以旋转90度以适应任何可能的情况。 我的任务是制作一个应用程序,计算应该选择哪些块以及选择多少块,以便所有的块都适合给定的墙。在本例中,为36 x 36 注意:开口应尽可能少地填充瓷砖,这意味着较大的瓷砖优先 我应该使用哪种算法放置瓷砖 另一个例子。字段30 x 30的绘制方式如下: 50 x 50 假设您正在寻找一般案例的答案,我很抱歉地说-但这个问题是。这基本上是一个二维的变化 子集求和问题:给定一组

我有一块36 x 36英寸宽和高的瓷砖

所以我有8x8,6x6,6x8,4x8块,它们可以旋转90度以适应任何可能的情况。 我的任务是制作一个应用程序,计算应该选择哪些块以及选择多少块,以便所有的块都适合给定的墙。在本例中,为36 x 36

注意:开口应尽可能少地填充瓷砖,这意味着较大的瓷砖优先

我应该使用哪种算法放置瓷砖

另一个例子。字段30 x 30的绘制方式如下:

50 x 50


假设您正在寻找一般案例的答案,我很抱歉地说-但这个问题是。这基本上是一个二维的变化

子集求和问题:给定一组
S
和一个数字
x
——找出是否有
S
的子集求和到
x

很容易看出,通过将子集和问题简化为大小为
1*x
的“字段”,对于
s
中的每个
s
,我们就有了一个tile
1*s
——一个问题的解决方案也是另一个问题的解决方案

因此,这个问题没有已知的多项式解,大多数人认为多项式解并不存在。
但是,请注意,这里也可以使用一种方法。

因为amit给出了这个方法,所以我将具体说明这个方法。对于这四个块大小,并假设它是偶数(维度为偶数且>=6等),可以使用半贪婪算法:

第一个目标是最大化8x8块的数量。要做到这一点,您需要计算出每个方向需要多少
6
大小的块。对于每个维度,只需检查是否可被8整除。如果它不可除,减去6。重复,直到可分割(不应超过3次尝试)

不管花了多少时间,这就是您在该维度中所需的6x6块。把它们做成一个长方形,放在一个角落里。从8x8块中形成另一个矩形,并将它们放在相对的角上。这两个矩形的角应该接触

所以现在你可能有一些剩余的空间,在相对的角上有两个矩形。我们知道每个维度的一个维度可以被8整除,一个维度可以被6整除。简单的解决方法是用适当旋转的6x8块填充,但这不能保证最大数量的大(8x8)块。例如,使用50x50,您将剩下两个18x32的矩形。您可以用12块6x8瓷砖填充它们。每个块都不能比12块做得更好,但可以在其中安装更多的8x8块

如果这不重要,那你就完了(万岁)。这样做的好处是,您永远不需要使用4x8模块


如果确实要最大化8x8块,则必须采取另一步骤。我们在这里集中讨论可被6整除的维度,因为8很容易。我们可能需要的每种尺寸(8x8,6x8,4x8)堆栈都非常完美

另一方面,只有3个可能的数字:6、12和18。如果是其他原因的话,第一步做得不对。然后采取以下行动:

  • 对于6,添加一行6x8(无优化)
  • 对于12,添加一行4x8和一行8x8
  • 对于18,添加一行4x8、一行6x8和一行8x8
完成了


要查看差异,这里我们有两个50x50网格:

Blue  - 8x8
Red   - 6x6
Green - 6x8
Gray  - 4x8

第一个例子给出了总共49个块。蓝色是一个32x32区域(16个块),红色是18x18(9个块),其余的只是用6x8(24个块)填充


本例仍给出49个总数,但还有更多的8x8块。这里我们有24个大块,而不是上一个示例中的16个。现在还使用了4x8块。

在Python中:

def aux(x):
    # in h we store the pre-calculated results for small dimensions
    h = {18:[6,6,6], 16:[8,8], 14:[8,6], 12:[6,6], 10:[6,4], 8:[8], 6:[6], 4:[4]}
    res = []
    while x > 18: 
        # as long as the remaining space is large, we put there tiles of size 8
        res.append(8)
        x -= 8
    if x not in h:
        print("no solution found")
        return []

    return res + h[x]

def tiles( x, y ):
    ax = aux(x) # split the x-dimension into tiles
    ay = aux(y) # split the y-dimension into tiles
    res = [ [ (x,y) for x in ax ] for y in ay ]
    for u in res:
        print(u)
    return res


tiles( 30, 30 )
其基本思想是,您可以独立求解x和y,然后将这两个解组合起来


编辑:正如杜克林所说,该代码愉快地使用了4x6和4x4块,这与要求相反。然而,我认为只有在没有其他办法的情况下,它才能做到这一点。因此,如果结果包含这些块,那么没有这些块就没有解决方案。如果你没有现成的Python,你可以在这里使用以下代码:,只需按源代码上方的fork键。

在这种情况下,所寻求的解决方案似乎不是通用的,但我可能弄错了。你如何更改该算法以使其解算2D变体?@harold我还不确定,但我认为,通过增加问题的维度,并根据通过放置平铺创建的新(2)个矩形将每个问题划分为子问题。现在还不确定具体是如何实现的,这就是为什么我只给出了一个指向这个解决方案的指针,并指出它可能会被利用。NP完全并不意味着它不可行。这完全是问题大小的问题。现在可以跳过8x8 can块,因为它们被表示为两个相邻的4x8块(以2种方式)。所以,90度之后。旋转我们剩下的是6x6,6x8,8x6,4x8,8x4。这可能没那么多…@瓦尔多我同意,我指的是问题的一般情况。显然,解决一个小的NP完全问题(例如,8个城市的TSP)很容易。你有每种类型的特定数量的街区,还是每个街区的数量不受限制?街区的数量不受限制。这只是把玻璃块放在墙上的开口处。软件应该确定放置块的最便宜的方法,即块越少越好,但仍然可以填充整个空间。我有一个软件可以这样做,但我没有访问源代码的权限,所以我必须从Scratch将其重新编译成另一个应用程序。是的,这可能是背包问题,我这些天会很忙。我必须分析到目前为止我拥有的东西,所以我需要时间。你是否假设有一个4x4块(我的Python生锈了)?(通常,在没有太多解释的情况下发布(非伪)代码不是一个好主意