【问题标题】:How to generate a domino-tiling of a square?如何生成正方形的多米诺骨牌?
【发布时间】:2019-04-25 09:13:24
【问题描述】:

简短说明:

我正在尝试用多米诺骨牌或换句话说用 2x1 和 1x2 瓷砖生成正方形的平铺。

有时我的算法会以某种方式放置垂直平铺,这使得无法填充最后一行。

我的当前方法是用 0 初始化一个网格(比如 8x8 网格)。 我在网格中用 1 表示水平图块的左半部分,用 2 表示右半部分。

因此垂直瓦片的上半部分是3,下半部分是4。

然后我从左到右遍历网格的每一行,在 0 的位置放一个图块:

  • 每当我在网格的右边缘或右边的空间不为 0 时,我都会放置一个垂直平铺 (3)。
  • 当我在底部边缘时,我(可以)只放置水平瓷砖。
  • 如果以上都没有设置值,我会设置一个随机值(1 或 3)。

每当我放置一个瓷砖(1 或 3)时,我也会相应地为网格的相邻空间放置相应的一半。假设我在 (i,j) 上放了一个 1,然后在 (i,j+1) 上放了一个 2。

StoneMatrix = int[8][8];

for (int i = 0; i < StoneMatrix.length; i++) {
    for (int j = 0; j < StoneMatrix.length; j++) {
        if (StoneMatrix[i][j] != 0){
            //field already set as a tile
            continue;
        }

        if (i == StoneMatrix.length - 1) {
            //bottom row
            StoneMatrix[i][j] = 1;
            StoneMatrix[i][j + 1] = 2;
            continue;
        }

        if (j == StoneMatrix.length - 1) {
            //right edge
            StoneMatrix[i][j] = 3;
            StoneMatrix[i + 1][j] = 4;
            continue;
        }

        if (StoneMatrix[i][j + 1] != 0) {
            //field to the right taken.
            StoneMatrix[i][j] = 3;
            StoneMatrix[i + 1][j] = 4;
            continue;
        }

        StoneMatrix[i][j] = putOneOrThreeRandomly();
        putCorrespondingAdjacentTile();
    }
}

我觉得必须有一种简单或更容易的方法来生成这种平铺,但我还找不到。 我正在寻找的是一些来源,其中描述了这种生成算法,或者是一个简单的解决方案,可以修复我的错误。

【问题讨论】:

    标签: generated tiling


    【解决方案1】:

    最佳多米诺拼贴

    通过m 棋盘和2x1 多米诺骨牌创建任意n 的随机最大平铺。当n*m 是偶数时,平铺就完美了。

    理论

    考虑棋盘的白色和黑色方块。多米诺骨牌必须同时覆盖白色和黑色方块。因此,如果存在一些完美的平铺,则可以将解转化为如下图:每个棋格成为一个顶点,如果多米诺骨牌覆盖两个相邻的瓷砖,则两个顶点相连。这将产生一个二分图(所有边都有一个白色和一个黑色顶点)和(最大)匹配图。

    因此,给定任何大小的网格(或任何形状),如果我们能够解决二分图中的最大基数匹配问题,我们可以将解决方案转换为多米诺骨牌。

    实施(概念证明)

    要解决上述图问题,将其转换为最大流量问题,并与 Ford Fulkerson 一起解决。将源节点连接到所有白色瓷砖,将汇节点连接到所有黑色瓷砖。仅当它们是国际象棋网格上的邻居时,白色瓦片才指向黑色瓦片。求解所有容量为 1 的边。节点之间使用的边表明将在此处放置多米诺骨牌。

    示例

    考虑一个 2 行深 4 列宽的棋盘。白色方块是 {0, 1, 2, 3},黑色方块是 {4, 5, 6, 7}

    +---+---+---+---+
    | 0 | 4 | 1 | 5 |
    +---+---+---+---+
    | 6 | 2 | 7 | 3 |
    +---+---+---+---+
    

    现在假设我们有两个额外的节点,8 源和9 接收器。然后找到最大流量的图表如下所示。请注意,所有边的容量均为 1。

    0: 4, 6
    1: 4, 5, 7
    2: 4, 6, 7
    3: 5, 7
    4: 9
    5: 9
    6: 9
    7: 9
    8: 0, 1, 2, 3
    

    在运行 Ford-fulkerson 之后(使用随机 DFS 获得有趣的解决方案 - 如果您每次都想要一个无聊的逐行解决方案,请使用 BFS),我们可能会发现使用了以下边。请注意,涉及源/汇节点的边已被省略,因为它们对于重建平铺没有用。

    0-4
    2-6
    1-7
    3-5
    

    最后,这对应于下面的平铺

    +-----+---+---+
    | 0 4 | 1 | 5 |
    +-----+   |   |
    | 6 2 | 7 | 3 |
    +-----+---+---+
    

    我还在这里用 Java 创建了一个概念证明:https://github.com/forsythe/domino_tiling。如果你想看到它的实际效果,这里有一个 16x16 的输出:

    【讨论】:

      【解决方案2】:

      我通过将布尔值设置为 true 来“解决”了这个问题,每次我到达无法正确填充网格的状态时。

      然后在生成方法结束时,如果布尔值为 false,则网格有效或布尔值为 true,我重新启动该方法。我认为基本上是一个肮脏的“反复试验”。

      这不是我想要的解决方案,但它有效。所以我不回答这个问题。

      【讨论】:

        猜你喜欢
        • 2022-08-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多