如何以高效简便的方式解决5 * 5立方体

时间:2015-07-13 20:11:29

标签: algorithm recursion dynamic-programming

有5 * 5立方体拼图名为快乐立方体问题,对于给定的垫子,需要制作立方体。 http://www.mathematische-basteleien.de/cube_its.htm#top

就像6个蓝色垫子一样 - enter image description here

从以下垫子中,需要派生一个立方体 - enter image description here

这种方式还有3个解决方案。 就像第一只小熊一样

对于这样的问题,我能想象的最简单的方法是基于递归,对于每个立方体,我有6个位置,并且对于每个位置,我将尝试检查所有其他配合,哪个适合,我将再次递归地再次解决。就像找到每个立方体的所有排列,然后找到哪个最适合。所以动态编程方法。

但是我在递归中犯了很多错误,所以有没有更好的方法可以用来解决它?

我从提供的每个垫子或图表中制作了矩阵,然后我每隔90次顺时针旋转它们4次,然后逆时针旋转。我翻转数组并做同样的事情,现在对于上面的每一次迭代,我都要重复其他立方体的步骤,所以再次递归。

 0 0 1 0 1
 1 1 1 1 1
 0 1 1 1 0
 1 1 1 1 1
 0 1 0 1 1
-------------
 0 1 0 1 0
 1 1 1 1 0
 0 1 1 1 1
 1 1 1 1 0
 1 1 0 1 1
-------------
 1 1 0 1 1
 0 1 1 1 1
 1 1 1 1 0
 0 1 1 1 1
 0 1 0 1 0
-------------
 1 0 1 0 0
 1 1 1 1 1
 0 1 1 1 0
 1 1 1 1 1
 1 1 0 1 0
-------------

1st - block is the Diagram
2nd - rotate clock wise
3rd - rotate anti clockwise
4th - flip

仍在努力理清逻辑。

1 个答案:

答案 0 :(得分:2)

我无法相信这一点,但实际上我在2009年写了一套脚本来解决这个问题的蛮力解决方案,对于简单的立方体案例。我只是把代码放在Github上:https://github.com/niklasb/3d-puzzle

不幸的是,文档是德语的,因为这是我的团队理解的唯一语言,但源代码注释是英文的。特别是,请查看文件puzzle_lib.rb

这种方法确实只是一种简单的回溯算法,我认为这是一种方法。我不能说它是 easy ,据我记得三维方面有点挑战性。我实现了一个优化:预先找到所有对称性,只尝试一个片段的每个唯一方向。这个想法是,这些作品的特征越多,放置碎片的选择就越少,所以我们可以提前修剪。在许多对称的情况下,可能存在很多可能性,我们只想检查那些对称的唯一对称。

基本上算法的工作原理如下:首先,将固定顺序分配给立方体的边,例如,将它们编号为0到5。然后执行以下算法:

def check_slots():
    for each edge e:
        if slot adjacent to e are filled:
            if the 1-0 patterns of the piece edges (excluding the corners)
                   have XOR != 0:
                return false
            if the corners are not "consistent":
                return false
    return true

def backtrack(slot_idx, pieces_left):
    if slot_idx == 6:
        # finished, we found a solution, output it or whatever
        return
    for each piece in pieces_left:
        for each orientation o of piece:
            fill slot slot_idx with piece in orientation o
            if check_slots():
                backtrack(slot_idx + 1, pieces_left \ {piece})
            empty slot slot_idx

角落的一致性有点棘手:角落必须由相邻的一个部分填充,或者必须可以从尚未填充的槽中进入,即不会被已经分配的部分切断。

当然你可以忽略掉一些或所有的一致性检查,只检查最后,因为只有8 ^ 6 * 6!整体可能的配置。如果你有超过6件,早期修剪就变得更加重要。