将Zoombinis安置在Cajun上尉的渡船上的算法?


12

我最近一直在玩《Zoombinis的逻辑之旅》的重发行,并尝试实现一些可以解决各种难题的计算机算法。我被卡在如何解决卡琼船长的渡船难题上。

对于那些不熟悉的人,Zoombini是一种具有4种属性的生物:头发,眼睛,鼻子和脚。这些属性中的每一个都有5个可能的值。例如,Zoombini的脚可以是轮子,溜冰鞋,运动鞋,弹簧或螺旋桨。这是Zoombini的例子,头发凌乱,眼镜,鼻子绿色和运动鞋凌乱:

在渡船难题中,任务是在渡船的16个座位上安排16个Zoombinis集合。该布置必须遵守以下规则:任何两个正交相邻的座椅必须由共享至少一个特征的Zoombinis占用。如果两个Zoombinis有不同的发型,不同的眼睛,不同的鼻子,不同的脚从彼此,他们可能不会坐在旁边给对方。

座位的安排会随着级别的变化而变化;为了具体起见,让我们集中讨论“非常困难”级别,其中16个座位以4×4网格排列。这是合法放置15个Zoombinis的示例,但最终站在码头上的Zoombini不能放在最后一个空座位上,因为她不会与右侧的Zoombini分享任何功能:

拼图即将完成的示例

有16个!≈21万亿可能的Zoombinis分配给座位。因此,简单地遍历所有可能的任务以查看其是否合法是不现实的。我可以采用哪些启发式方法明智地解决此问题?


2
它使我想起了数独,而数独解算器通常实现某种回溯。
mattecapu '16

2
如果您准备好并愿意研究一些更复杂的文献,则可以通过搜索找到有用的信息Subgraph Isomorphism Problem。问题是要在另一个图中找到一个图。在您的情况下,子图将是座位(边缘是邻接),而父图将是zoombinis,其中连接将是共享特征的存在。请注意,通常该问题是NP完全的,通常也通过回溯来解决,但是对于某些特殊情况(您的图形很可能是这种情况),多项式甚至线性解都是可能的。
Ordous

这是一个好主意,我小时候喜欢zoombinis-我可能会做同样的事情!
AlexFoxGill

Answers:


8

感谢@mattecapu提供有用的Google搜索术语“回溯算法”。那给了我所需的食物。

我目前的直觉是,最好先填充有4个邻居的中央座位,最后保留只有2个邻居的角落座位。因此,我将16个空座位按以下顺序排列到链接列表中:

13   5   6  14

 7   1   2   9

 8   3   4  10

15  11  12  16

这是一些伪代码,描述了我编写的函数。您向它提供一个列表,其中包含16个Zoombinis和一个指向链表中第一个座位的指针。

function recursively_assign_seat(zoombini_list, seat):

    if zoombini_list is empty:
        return True

    else:
        for each z in zoombini_list:

            for each n in seat.neighbors:
                if not allowed_as_neighbors(z, n):
                    next z

            seat.occupant ← z
            if recursively_assign_seat(zoombini_list.remove(z), seat.next):
                return True
            else:
                seat.occupant ← None

        return False

实际上,它运行起来非常快!我对此非常满意。

我还没有完全确信我已经以最佳的顺序安排了座位表。这个问题总共有24个约束条件,理想的座椅填充顺序会在座椅填充过程中尽早面对这些约束,从而使不可行的分支尽快被最大程度地修剪掉。


1
当您填充时,您8仅与相邻2,但您可能同时填充97与和相邻的3。解决问题的方法不错!
AlexFoxGill

进行编辑;不过,仍然不确定由内而外的方法是否比仅逐行填充要好。也许我会做一些时序测试。
thecommexokid
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.