【问题标题】:Generalizing the algorithm for domino tiling?推广多米诺平铺算法?
【发布时间】:2011-11-12 15:09:52
【问题描述】:

this earlier question 中,OP 提出了以下问题:

给定一个矩形网格,其中一些正方形是空的,一些是填充的,如果没有两个多米诺骨牌重叠并且填充的正方形顶部没有多米诺骨牌,可以放置到世界中的 2x1 多米诺骨牌的最大数量是多少?

这个问题的(非常漂亮!)答案认识到这相当于在特殊构造的图中找到最大二分匹配。在该图中,每个空方格都有一个节点,该节点通过一条边链接到它的每个邻居。然后,每个多米诺骨牌对应于图中的一条边,这样它的端点就不会被任何其他边覆盖。因此,任何不共享顶点(匹配)的边集都对应于多米诺骨牌的排列,反之亦然。

我的问题是对前面这个问题的概括:

给定一个矩形网格,其中一些正方形是空的,一些是填充的,可以放置到世界中的 M x N 多米诺骨牌(对于给定的 M 和 N)的最大数量是多少,使得没有两个多米诺骨牌重叠并且没有多米诺骨牌在一个实心正方形的顶部?

我看不到如何将其转换为前一个案例中所做的匹配问题。但是,我也看不出这个问题会立即成为 NP-hard 的任何特殊原因,因此该问题可能存在多项式时间解决方案。

有解决这个问题的有效算法吗?或者有没有人有减少表明这个问题是 NP-hard 的?

非常感谢!

【问题讨论】:

    标签: algorithm puzzle tiling


    【解决方案1】:

    真是个好问题。这个问题等价于在一个特殊的图上找到大小最大独立集(或最大团大小)——顶点将是 MxN 矩形的所有可能位置,如果它们发生碰撞,边将连接这两个位置。然后找到最大独立集的大小产生结果。反之亦然,我们可以将边定义为连接两个不碰撞的位置,然后我们会寻找最大的团大小。无论如何,这两个图都不是无爪图也不是完美的,所以我们不能使用多项式解决方案来找到最大独立集/团。

    所以,我们可以尝试将最大独立集问题转换为这个平铺问题,但我找不到如何将一般图转换为此的方法,因为您无法转换例如将 K1,5 子图引入到瓦片中。

    【讨论】:

      【解决方案2】:

      从立方平面单调One-in-three 3SAT 减少后,1x3 瓷砖很难。我们必须建立一些“电路”来对公式进行编码。

      “门”:


      X********Y
      

      强制XY 中的一个被外部覆盖。用于链接变量及其否定。


      Y***
         *
         *
        ooo  ****
        * *  *  *
        * *  *  *
        X ****  Z
      

      强制不覆盖或全部覆盖 XYZ。用于复制X 或销毁同一事物的三个副本。使用长度为 3 L 的线材可以或多或少任意地塑造电线。


      *******************
      *        *        *
      *        *        *
      X        Y        Z
      

      强制 XYZ 之一被外部覆盖。每个子句一个。

      【讨论】:

      • 看起来是一种很有前途的方法,但我无法遵循——例如在您的最后一个示例中,我看到最佳(5 块)覆盖物覆盖 X、Y 和 Z 中的任意 2 个,或全部 3 个,但不完全是您所说的 1 个。此外,我不确定“输入”如何在您的方案中路由到“输出”——例如对于您的第 3 个 sn-p,孤立地我可以看到有一个 9-tile 最佳配置,涵盖所有 X、Y 和 Z,但是例如如果 X 已经被另一个电路的“输出”覆盖,那么在现在最优的一组 8 块配置中,Y 和 Z 可能被覆盖或未被覆盖。
      • @j_random_hacker 覆盖 X、Y 和 Z 中的任意 2 个,或全部 3 个我没有看到全部 3 个。想法是小工具覆盖了两个接口,还有一个是外界。我们通过将它们的接口叠加在一起的方式将这些小工具放在一起,并且线路上的值由接口从哪一侧覆盖来指定。
      • 我认为这是一个很有前途的方法!但是,我还不相信。你能说明简单输入 {abc} 是如何解决的吗?另外,如何解决 {abc,a'bc} ? (解释瓷砖铺设解决方案如何为您提供满足子句的变量分配)
      • 如果图形是平面的,但有些节点的度数大于四,你会怎么做?您如何将这个平面图映射到网格世界中?
      • @templatetypedef 基本上,我们在嵌入之前进行 ternerize。事实证明,已经知道三次平面单调三分之一 3SAT(最大 3 级,无负字面量)很难,所以我将切换源问题,同时避免正负问题电线交叉。
      【解决方案3】:

      我要做的第一件事是创建第三种状态:“空,但无法访问”。您可以轻松地证明在 l*w*m*n 时间内无法到达每个图块(其中 l 是世界的长度,w 是世界的宽度,m 和 n 是图块的尺寸)。这将减少您的空间,以便可以访问任何空的瓷砖。请注意,您可能有可到达的瓷砖岛屿。最简单的例子是世界被切成两半。这有助于递归的努力,其中每个可达性岛都被视为一个独立的世界。

      现在我们正在处理一个岛(可能是方形也可能不是方形),您基本上有一个 2D 背包问题的特殊情况,已知它是 NP 难的(@ 987654321@ 在以前的工作下)。你的通过在背包中添加固定位置来增加问题的复杂性,但通过使所有包裹尺寸相同来降低复杂性(稍微)。

      【讨论】:

      • 编辑:提供了更好的引用。
      • NP-hard 问题的特殊情况不一定是 NP-hard。例如,“无环图上的哈密顿路径”在 P 中。
      • @Tom 这是真的。但是,当您增加 NP 难题的复杂性时,我无法想象它不会至少保持 NP 难题。
      • 对于 1x3 多米诺骨牌,2D 背包在 P 中,对吗?在背包中添加固定位置确实会使问题变得更难,但不一定是 NP-hard。
      • @Tom 用于 MxN 多米诺骨牌,它已经是 NP 难的,添加固定位置只会增加其复杂性。
      【解决方案4】:

      这个问题绝对是 NP 难的,我可以证明这一点。从 3-SAT 减少到这个问题。具体来说,它是从 3-SAT 减少到这个问题的子问题,其中多米诺骨牌是 1x3。其他特定尺寸可能还有其他减少,但这个绝对有效。

      本质上,在这种简化中,我们将使用多米诺骨牌位置来编码真假。具体来说,我将采用与其他解决方案相同的符号,也就是说,我将使用星号来表示网格上的开放空间。我还将使用三个大写字母的集合来表示多米诺骨牌,使用小写字母来表示“信号”,这些“信号”是可能会或可能不会被填充的空格,具体取决于系统的状态。

      要将 3-SAT 问题嵌入到这个空间中,我们需要一组我称之为小工具的东西,它们只允许某些状态成为可能。这些小工具中的大多数都会有固定数量的多米诺骨牌。例外情况是代表子句的小工具,如果子句为真(满足),则将有一个额外的多米诺骨牌,但当它为假(不满足)时则不会。我们可以使用路径互连这些小工具。这将使我们能够构建一个 3-SAT 电路。我们将有一个基数的多米诺骨牌,因为每个路径和小工具都将采用标准数量的多米诺骨牌,我们可以将它们相加得到一个基数 k,然后每个子句小工具可以有一个额外的多米诺骨牌,如果它是真的,所以如果所有子句可以为真(因此满足表达式)并且有 n 个子句,那么多米诺骨牌的最大数量将是 n+k。如果不是,那么最大数量将小于 n+k。这是还原的基本形式。接下来我将描述这些小工具并举例说明。

      与另一个答案类似,我们将有两个位置对给定变量编码真假。因此,我将从一个可以位于两个可能位置的图块开始。

      ****
      

      这可以用一张多米诺骨牌来覆盖

      AAA* or *AAA
      

      显然,这不能用 2 多米诺骨牌覆盖,而用 0 多米诺骨牌覆盖它永远不会是最大的。出于我的目的,我们将考虑用突起来表示值“假”,而没有突起来表示“真”。所以我们可以将这部分视为携带两个信号:

      x**y
      

      在这种情况下,只会覆盖 x 或 y 中的一个,因此我们可以认为信号是 x 和 x 的逻辑非。就我们的目的而言,凡是涵盖的都是假的,凡是不涵盖的都是真的。接下来,我们可以简单地通过直线可以弯曲的路径传输信号。如果我们有

      x*****y
      

      我们将再次恰好有两个多米诺骨牌,并导致 x 或 y 被覆盖,但不能同时覆盖。

      ***y
      *
      *
      x
      

      将具有完全相同的行为。所以我们可以使用它来创建长度为 3 的长而弯曲的路径。但是,并非我们可能想要使用的所有长度都是 3 的增量,所以我们需要一个额外的小工具来移动不同的距离。我称之为提琴手小工具,它的唯一目的是将信号移动到稍微不均匀的距离以使事物成功连接。它的输入来自 x,输出到 y,它只传输相同的信号。它看起来像这样:

       ***y
       *
      **x
      

      它总是恰好包含两个多米诺骨牌,并以以下两种方式之一填充:

       BBB*     ABBB
       *        A   
      AAA      *AX  
      

      但是,如果我们要对 3-SAT 进行建模,我们需要的远不止这些。具体来说,我们需要一些方法来对子句进行建模。为此,我们有一个小工具,如果该子句为真,则可以在其中打包一个额外的多米诺骨牌。当一个或多个输入为真时,该子句为真。在这种情况下,这意味着当至少有一个输入没有突出时,我们可以添加一个额外的多米诺骨牌。它看起来像这样:

      *x*y*
        *
        z
      

      如果为了清晰起见,我们为每个路径添加一个额外的路径,那么它看起来像这样:

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

      如果 x、y 和 z 都是假的,那么它们都会有突起,并且会像这样被填充 这个:

       A B
       C D
       C D
      *C*D*
        *
        EEEF
      

      其余的多米诺骨牌 A、B 和 F 继续沿着某处的路径前进。如果至少有一个输入为真,那么我们可以像这样打包一个额外的多米诺骨牌 (G):

       C B         A D         A B
       C D         C D         C D
       C D    or   C D    or   C D
      GGGD*       *CGGG       *CGD*
        *           *           G
        EEEF        EEEF        GEEE
      

      但是,即使所有输入都为真,我们也不能打包多个多米诺骨牌。这种情况看起来像这样:

       C D
       C D
       C D
      *****
        *
        *EEE
      

      如你所见,我们只能在空白处插入一个额外的多米诺骨牌,而不是两个。

      现在,如果条款不再重复,那么我们就完成了(或几乎完成了)。但是,它们可以重复,所以接下来,我们需要一个信号分离器,以便一个变量可以出现在 多个术语。为此,我们使用以下小工具:

      y*** ***z
         * *
         ***
         ***
          x
      

      在这个小工具中,x 是输入,y 和 z 是输出。在这个小工具中,我们总是可以打包 5 张多米诺骨牌。如果 x 比包装 5 块多米诺骨牌突出,则始终需要覆盖 y 和 z。如果 x 不突出,则不需要覆盖 y 和 z。 x 不突出的包装是这样的:

      yAAA BBBz
         C D  
         CED 
         CED  
          E 
      

      当 x 确实突出时(我们用 X 表示多米诺骨牌的末端突出到空间 x 中),最大包装必然涵盖 y 和 z:

      AAAC DBBB
         C D
         C*D
         EEE
          X
      

      我会花一点时间注意,当 x 没有以 y 或 z 突出的方式突出时,可以用五张多米诺骨牌打包它。但是,这样做会导致可能为真(不突出)的术语变为假(突出)。仅通过不必要地变为假来允许某些术语(不是变量,而是子句中的实际术语)在值上有所不同,永远不会导致能够满足否则无法满足的表达式。如果我们的 3-SAT 表达式是 (x | y | z) & (!x | y | !z) 那么让 x 和 !x 都为假只会让事情变得更难。如果我们让某事物的两端都为真,这将导致不正确的解决方案,但我们在此方案中不这样做。根据我们的具体问题来构建它,不必要地突出永远不会导致更多的多米诺骨牌能够在以后被打包。

      有了路径和这三个小工具,我们现在可以解决平面 3-SAT,这将是 3-SAT 的子问题,如果我们绘制一个图形,其中术语和子句是顶点并且每个之间都有一条边术语和包含该术语的每个子句,即图形是平面的。我相信平面 3-SAT 可能是 NP 难的,因为平面 1-in-3-SAT 是,但如果不是,我们可以使用小工具进行信号交叉。但它真的很复杂(如果有人看到更简单的方法,请告诉我)所以首先我将做一个用这个系统解决平面 3-SAT 的例子。

      因此,一个简单的平面 3-SAT 问题将是 (x | y | z) & (!x | y | !z)。显然,这是可以满足的,使用 y 为真的任何赋值或其他几个赋值。我们将这样构建我们的多米诺骨牌问题:

          *******
          *     *
          *     *
       ****   ***
       *       *
      ***      ****
        *         *
        *         *        
        * ******* *
        * *     * *
        * *     * *
       *z*x*   *****
         *       *
         **** ****
            * *
            ***
            ***
             *
             *
             *           
             y
      

      请注意,我们必须在顶部使用提琴手才能正确分配空间,否则这将大大降低复杂性。

      将小工具和路径的多米诺骨牌总数相加,我们有 1 个拆分器(5 个多米诺骨牌)、两个提琴手(每个 2 个多米诺骨牌)和总共 13 个常规路径,总计 5 + 2*2 + 13 = 22 多米诺骨牌保证,即使条款无法满足。如果可以,那么我们将有 2 个多米诺骨牌,总共可以填充 24 个。24 个多米诺骨牌的最佳包装如下:

          QRRRSSS
          Q     T
          Q     T
       OPPP   *UT
       O       U
      *ON      UVVV
        N         W
        N         W        
        M IIIJJJK W
        M H     K X
        M H     K X
       *zGH*   LLLX*
         G       *
         GEEE FFF*
            B D
            BCD
            BCD
             C
             A
             A
             A
      

      这个平铺包含24个多米诺骨牌,因此我们可以知道原始表达式是可满足的。在这种情况下,平铺对应于使 y 和 x 为真而 z 为假。请注意,这不是唯一的平铺(也不是唯一令人满意的布尔值分配),但没有其他平铺可以增加超过 24 个的平铺,因此它是最大平铺。 (如果您不想计算所有的多米诺骨牌,可以注意我使用了除 Y 和 Z 之外的所有字母。)

      如果最大平铺包含 22 或 23 个多米诺骨牌,那么我们会知道其中一个条款不满足(无法放置 GGG 和/或 LLL 多米诺骨牌),因此我们会知道原始表达式不能满足。

      为了确保即使平面 3-SAT 不是 NP-hard 也能做到这一点,我们可以构建一个允许路径交叉的小工具。不幸的是,这个小工具有点大而且复杂,但它是我能弄明白的最小的。我将首先描述各个部分,然后描述整个小工具。

      第 1 部分:交叉点。 x 和 y 是输入。 a、b 和 c 是输出。它们需要使用其他小工具组合起来,才能将 x 和 y 实际传递到彼此的另一侧。

         ***c
         *
        ***
        * *
        * *
        * *
        ***
        ***
       ax*yb
      

      这个小工具总是正好适合 7 块多米诺骨牌。有四种可能的输入组合。如果两个输入都没有突出(两者都为真),则没有输出将突出,并将填充如下(tt1)或(tt2)。如果只有输入 x 突出,那么只有 c 会突出,如下面的 (ft) 所示。如果只有输入 y 突出,则输出 a 或 c 将突出,如下面的 (tf) 所示。如果输入 x 和 y 都突出,则输出 c 突出,如下面的 (ff) 所示。

       (tt) AAAc         (ft) AAAc         (tf) AAAc         (ff) BAAA     
            *                 *                 *                 B        
           BBB               BBB               BBB               CBD       
           C D               C D               C D               C D       
           C D               C D               C D               C D       
           C D               C D               C D               E G       
           EEE               EEE               EEE               EFG       
           FFF               FFF               FFF               EFG       
          aGGGb             aXGGG             GGGYb             aXFYb      
      

      我没有包括在 (ft) 或 (tf) 场景中可以覆盖 c 而不是 a 或 b 的可能性。这在这个小工具的范围内是可能的,但是一旦与其他小工具组合形成完整的交叉,如果这样做,它将永远不会导致大量的子句被满足,因此我们可以排除它。考虑到这一点,我们可以观察到,在这种情况下,输入 x 的值等于 b & c 的值,输入 y 等于 a & c 的值(请注意,这将是合乎逻辑的,或者更确切地说而不是逻辑,如果突出被认为是真实的而不是虚假的)。所以我们只需要对c进行拆分,然后使用逻辑和gadget将c的值分别与a和b连接起来,就可以成功完成我们的交叉了。

      逻辑 and 是我们迄今为止最简单的小工具,它看起来像这样:

        ****
        *
       x*y
      

      您实际上可能会注意到,在交叉点小工具的顶部嵌入了一个。此小工具将始终包含恰好 2 个多米诺骨牌。一个将在顶部作为输出。另一个用作开关,只有当 x 和 y 都为真(不突出)时才会水平定向,否则垂直定向,如下图所示:

       BBB*     ABBB     ABBB     ABBB
       *        A        A        A   
      AAA      XAy      xAY      XAY  
      

      因此,我们可以通过拆分 c 然后添加其中两个门来完成交叉,一个用于 a & c,一个用于 b & c。将它们放在一起还需要添加一些提琴手小工具,如下所示:

                   ******* ****
                   *     * *  *
                   *     ***  *
                  ***    *** ***
                    *     *  *
                 ****     *  ****
                 *        *     *
                 *     ****     *
                ***    *       ***
                  *   ***      *
               ****   * *      ****
          y    *      * *         *    x
          *    *      * *         *    *
          * ****      ***         **** *
          ***         ***            ***
            **********x*y*************
      

      我不会为此填写示例平铺。如果你想看到它的实际效果,你必须自己做。所以,万岁!我们现在可以做任意的 3-SAT。我应该花点时间注意,这样做将是一个多项式时间变换,因为即使在最坏的情况下,我们也可以制作一个大网格,上面有所有变量及其对立面,所有项都在旁边,然后做O(n^2) 次交叉。因此,有一个简单的多项式时间算法可以解决所有这些问题,并且转换后的问题的最大大小是输入问题大小的多项式。 QED。


      编辑说明: 继汤姆·西尔格达斯(Tom Sirgedas)出色地发现拆分器小工具中的错误之后,我对答案进行了一些更改。从本质上讲,我的旧分离器看起来像这样,当 x 不突出时(而不是我想要的 5)可以像这样装满 6:

      y*** ***z   AAAC DBBB
         * *         C D
         ***         C*D
         ***         EEE
         *x*         FFF
      

      所以我修改了它,去掉了 x 两边的两个空格。这消除了 6 个 domino 包装,同时仍然允许 5-domino 包装,其中 y 和 z 在 x 未被覆盖时未被覆盖。

      【讨论】:

      • 看起来真的很不错(喜欢与门!)但我担心的一件事是你对正方形是否被覆盖的概念有点模糊。尽管您为后来的一些小工具解决了这个问题,但即使在您最基本的小工具x*****y 中,也不能保证平铺完全不会覆盖xy 之一:例如XXX*YYY 是有效的最大平铺。我认为您需要的是一个引理,保证如果存在多个最大平铺,并且其中至少一个使给定的正方形x 未被覆盖,那么我们可以假设x 在我们将其固定到另一个小工具时未被覆盖。
      • 当您说“如果最大平铺包含 24 或 25 个多米诺骨牌”时,您的意思是“如果最大平铺包含 25 或 26 个多米诺骨牌”吗?只是想确保我理解正确:)
      • @j_random_hacker:(最后一件事)我的意思是“22 或 23”。我第一次把多米诺骨牌数错了 2,然后当我修复它时,我错过了一个位置,所以这两个数字错了 2。对不起。接得好。现在已经修好了。
      • 在某些情况下可以与最大平铺相同,但前提是所涉及的变量不是满足子句的变量。例如,在平面示例中,我们可以使 z 和 !z 都突出(使两个值都为假)。这不会改变瓷砖的总数或满足的条款数量。如果在我们的系统中 z 和 !z 都为真(不突出),它就会被破坏,因为它会给出不正确的结果。但是允许 z 和 !z 都为假永远不会导致这个问题。这是证明中比较棘手的想法之一。我希望这个解释对你有意义。
      • FWIW,我在我的程序中发现了一个更简单的交叉小工具:pastebin.com/EuctLXTU
      【解决方案5】:

      致基思:

      伟大的工作和伟大的解释!不过,我写了一个程序来找到最大的平铺,它发现了一个缺陷。希望这可以解决! [更新:Keith 确实解决了问题!]

      请查看此链接: http://pastebin.com/bABQmfyX(您的小工具已分析,加上非常方便的 c++ 源代码)

      问题是下面的小工具可以用 6 块多米诺骨牌平铺:

      y*** ***z
         * *
         ***
         ***
         *x*
      

      -汤姆·西尔格达斯

      【讨论】:

      • 程序用法:将电路(如上图)复制到文本文件中。运行程序,第一个参数是文件名。
      • 啊,你是对的。我知道了。不过,我想我可以解决这个问题。该程序真的很漂亮,感谢您这样做。
      • @Keith:我添加了“搜索具有给定真值表的小工具”功能,并发现了一些巧妙的设计。然后,我想简化设计并找到了你的 AND 门(哈哈!它用作分离器)。更换有故障的分离器很简单,并且可以修复您的 3SAT 示例。但是,跨界小工具似乎仍然存在缺陷,我还没有找到修复方法。见图表:pastebin.com/pPYVc6RT
      • @Tom:这绝对是一个更简单的拆分器。整洁的。但是,您在分频器中更换分离器的方法有一个错误,因为您没有进行调整以使路径的长度都为 3 的倍数。具体而言,从分离器向上的路径是您的问题。如果您将分频器与我的(更复杂的)分离器一起使用,其中间距确实有效(请参阅上面的修订答案),它可以工作。而且我确信我们可以用你的分离器重做交叉,它只需要更多的空间摆弄。
      • @Keith:很酷,我会在今天晚些时候检查一下。另外,这是我的 hacky 真值表小工具搜索器:pastebin.com/f9BDUjE6。还有……对 2x2 多米诺骨牌有什么想法吗? :) :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-30
      • 2012-02-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多