使用算法X解决精确覆盖问题的Pentomino求解算法

时间:2015-05-09 21:53:17

标签: java algorithm

我正在研究这几天,最后决定在这里发布我的问题。我会详细解释你在做什么以及如何做。 继续之前。我浏览了维基百科和另外20个网站来解释这个问题,但它没有帮助我。

Dancing Links - Wikipedia

Knuth's algorithm x

其中一个更有用的网站:( Kanoodle)但是当我遇到问题时,解释非常糟糕。

问题:有多少种方法可以用W-,I-和L-五角星覆盖一个5xn的矩形。您可以翻转和旋转它们。您可能会问什么是Pentominos? Pentominos由5个方块组成,共同构成一个人物。例如W-Pentomino。

   | A | B | C
---------------
a  | 1 | 0 | 0 |
-------------
b  | 1 | 1 | 0 |    Imagine all the 1s together they build a big "W".
-------------       If you look at my picture it will be clearer.
c  | 0 | 1 | 1 |

我没有在5xn字段中实现W-,L-和I-Pentominos,而是开始考虑在5x3字段中填写“W”的所有可能方法。 像这样。 enter image description here 我的下一步是考虑一个类似于DLX-Knuth算法的矩阵,我想出了这个。黄色和橙色之间的绿线表示您可以将两者放在一起以获得另一个有效的解决方案。我的下一篇文章描述了这条绿线。 enter image description here

我注意到,如果我连续一行并检查此行下方或上方的任何其他行是否在同一列中没有1我有一个有效的解决方案。但我不知道如何实现它。在研究了几个小时后,我发现了另一种描述我的问题的方法。我拿了一个子集(我的W-Pentomino)并将其定义为这样。 ---picture.

然而,我再次无法实现这一点。

所以这是我的问题:你如何在JAVA中实现这个问题。我的做法好吗?你能用我的想法吗?如果是的话,你会怎样继续,如果不是,你会告诉我在我的想法中失败了吗?

这是我写的sofar代码。

package data;

public class PentominoWILDLX
{
    static Node h;          // header element

    static int cnt;         // count solutions

    public PentominoWILDLX()
    {
        h = new Node();     // init header element
        cnt = 0;            // init counter
    }


    public static void search (int k)           // finds & counts solutions
    {
        if(h.R == h)                            // if empty: count & done
        {
            cnt++; return;                      // choose next column c
        }
        Node c = h.R;                           // remove c from clumns
        cover(c);                               // choose next colun c
        for (Node r=c.D; r!=c; r=r.D)           // forall rows with 1 in c
        {
            for(Node j=r.R; j!=r; j=j.R)        // forall 1-elements in row
            {
                cover(j.C);                     // remove clumn
            }
            search(k+1);                        // recursion with k+1 << hier überpfüen ob ich ändern muss
            for (Node j=r.L; j!=r; j=j.L)       // forall 1-elemnts in row
            {
                uncover(j.C);                   // backtrack . unremove? << googlen
            }
            uncover(c);                         // unremove f c to coulmns
        }
    }



    public static void cover (Node c)           // remove clumn c
    {
        c.R.L = c.L;                            // remove header
        c.L.R = c.R;                            // from row list
        for (Node i=c.D; i!=c; i=i.D)           // forall rows with 1
        {
            for (Node j=i.R; i!=j; j=j.R)       // forall elem in row
            {
                j.D.U = j.U;                    // rmove row elemnt
                j.U.D = j.D;                    // from column list
            }
        }
    }

    public static void uncover (Node c)         // undo remove col c
    {
        for (Node i=c.U; i!=c; i=i.U)           // forall rows with 1
        {
            for (Node j=i.L; i!=j; j=j.L)       // for all elem in row
            {
                j.D.U = j;                      // unremove row ele,
                j.U.D = j;                      // to lumn list
            }
            c.R.L = c;                          // unremove header
            c.L.R = c;                          // to row list
        }
    } // end of class

    class Node                  // represents 1 element or header
    {
        Node C;                 // reference to column-header << h?,
        Node L;                 // left
        Node R;                 // right
        Node U;                 // reference up
        Node D;                 // down reference down

        Node()
        {
            C=L=R=U=D=this;     // 2*double-linked circular list
        }
    }   // end of class

    public static void main(String[] args)
    {

    }

}

1 个答案:

答案 0 :(得分:2)

要找到可以将Pentomino放入矩形的所有可能方法,您可以执行以下步骤:

  1. 找出pentomino的长度和长度,就像你要绘制一个矩形一样。
  2. 现在找到该矩形适合较大矩形的次数。例如,您有一个3x5矩形,较小的矩形用于W形状,它是3x3。 5-3 + 1 = 3.有3种可能的方法使W形状适合3x5平方(不翻转或旋转)。如果矩形是5x5并且我们仍在使用相同的pentomino,那么将有9种可能的不同方式来放置形状而不会翻转或旋转。使用公式:x = a - b + 1; y = c - d + 1; xy = z(没有旋转的可能方式)。 a =大矩形的长度; b =小矩形的长度; c =大矩形的宽度; d =小矩形的宽度。
  3. 由于我们正在处理矩形,您需要翻转形状并旋转它,每次执行此操作时,请在步骤3中执行相同的计算并将其添加到总计中。
  4. 第3步提出了另一个问题。如果翻转或旋转的形状与先前的形状相同,该怎么办?为了计算这个,采用x和y格式的形状,因此w形状将是:{(0,0),(1,0),(1,1),(2,1),(2,2)如果原点在左上角。取这些坐标并旋转它们。 (0,0) - &gt; (0,3)为第一个点逆时针旋转90度。要旋转前90度的任何点:(y,w - x - 1)w =矩形的宽度。要旋转接下来的90度,请执行:(y,h - x - 1)h =矩形的高度。要旋转最后时间,请重复(y,w - x - 1)。请记住,每次旋转宽度和高度都必须交换,因为它是一个矩形而不是一个正方形。如果这些旋转图形中的任何一个具有相同的坐标(它们不必具有相同的顺序),则不会使用步骤2检查该特定旋转。
  5. 最后你必须注意反射/翻转。这比旋转更容易。要水平翻转,只需做(w - x - 1,y); w =形状宽度。
  6. 以下是我用来解决这个问题的一些工作照片:

    寻找可能性:

    Find possibilities

    enter image description here

    enter image description here

    旋转(正方形和矩形): enter image description here

    enter image description here

    翻转: enter image description here