首先,我不一定在寻找一个完整的算法,我可以复制和粘贴,然后称之为一天。 任何"通用方法"解决方案对我来说都很好!
这整篇帖子是由一天缓慢的工作所激发的,偶然发现了这个网站,无法弄清楚他们是如何实现发电机的。
问题所在
对于那些不知道的人,"斑马拼图"或"爱因斯坦之谜"是一个著名的逻辑谜题,你可能以前遇到过。
完整的维基文章在这里,但我会发布相关的位。
There are five houses.
The Englishman lives in the red house.
The Spaniard owns the dog.
Coffee is drunk in the green house.
The Ukrainian drinks tea.
The green house is immediately to the right of the ivory house.
The Old Gold smoker owns snails.
Kools are smoked in the yellow house.
Milk is drunk in the middle house.
The Norwegian lives in the first house.
The man who smokes Chesterfields lives in the house next to the man with the fox.
Kools are smoked in the house next to the house where the horse is kept.
The Lucky Strike smoker drinks orange juice.
The Japanese smokes Parliaments.
The Norwegian lives next to the blue house.
Now, who drinks water? Who owns the zebra? In the interest of clarity, it must be
added that each of the five houses is painted a different color, and their inhabitants
are of different national extractions, own different pets, drink different beverages
and smoke different brands of American cigarets [sic]. One other thing: in statement
6, right means your right.
这一切都很好。 我在网上找到了几种简洁明了的方法来解决这个问题,尤其是使用约束编程。 然而,我感兴趣的是制作更多这种类型的谜题。
创造更多
显然,矩阵表示是思考这个问题的逻辑方式。 每列包含一个人、房子、他们喝什么、他们驾驶什么类型的汽车等。
我最初的想法是从随机生成的完整(即已解决)网格开始,然后(以某种方式)从已解决的版本创建唯一标识它的提示。 每次可以确定某些内容时,都会将其从网格中删除。
扯掉我在开头列出的站点,以下可用于解决网格的"提示"可以是以下类型:
人/动物/植物在给定的房子里生活/生长。
人/动物/植物不在给定的房子里生活/生长。
人/动物/植物与另一个人住在同一所房子里人/动物/植物。
人/动物/植物是另一个的直接邻居人/动物/植物。
人/动物/植物是其他动物/植物的左邻或右邻人/动物/植物。
人/动物/植物和另一间房子之间有一栋房子人/动物/植物。
人/动物/计划与另一间房屋之间有一所房子左侧或右侧的人/动物/植物。
人/动物/植物和另一个之间有两座房子人/动物/植物。
人/动物/计划与另一个之间有两宫左侧或右侧的人/动物/植物。
人/动物/植物从另一个向左或向右生活人/动物/植物。
你可以看到这些如何被概括、扩展等;
困难在于,使用我的方法(从完整的网格开始并生成这些提示),我不确定如何确保我创建的提示集绝对会产生目标网格。
例如,如果你说"英国人没有一棵松树",你就不能在谜题中的任何给定时间果断地将两件事配对在一起。 然而,如果只剩下两棵树需要解决,这实际上可能是一个决定性的证据。
我的想法是完全错误的方式吗?更好的方法是创建一个带有一些随机的、预定义的已知元素(即红房子在中间)的网格,然后使用这些提示作为构建规则来构建网格?
任何建议,要阅读的文章,要学习的编程技术等,将不胜感激!
下面是一个利用求解器的简单算法:
-
生成一个随机拼图实例。
-
构建与这个谜题实例相关的所有可能线索的集合 C。(可能的线索数量有限,实际上相当少:例如,如果有5所房子,则有5条"人A住在B家"形式的可能线索,"人A住在B房子旁边"形式的8条可能线索,依此类推。
-
选择C中线索的随机排列c 1,c2,...,cn。
-
设置 i = 1。
-
如果我>n,我们就完成了。线索的集合C是最小的。
-
设 D = C − { ci }。在线索集 D 上运行求解器并计算可能解的数量。
-
如果只有一个解决方案,则设置 C = D。
-
设置 i = i + 1 并返回步骤 5。
(您可以通过批量删除线索而不是一次删除一个来加快速度,但这会使算法更难以描述。
我对这个解决方案并不完全有信心,但这就是我的做法:
从随机解决方案开始(即绿屋持有抽LM的抛光剂,红房子持有抽丁香的爱尔兰油等)。 您可以将该解决方案视为语句之间关系的图形。 其中每个元素(波兰,红房子等)都通过"是"边缘或"无边缘"连接到所有其他元素(在我们的例子中,抛光以"是"边缘连接到温室和丁香带有"无边"(在许多其他边中,这个初始图是一个完整的方向图))。
现在,如果你随机拿走边,直到你留下一个最小的连接图,你应该有一个代表可解谜题的图。 将每个"是"边缘转换为"Foo is/do bar",将每个"no"边缘转换为"The Foo is not/not bar"。
直觉上,这对我来说听起来是正确的。 但同样,这绝不是一种正式或公认的方式,而且可能是完全错误的。
你也可以反过来做(这也会让你得到一个求解器):
- 生成 S,所有可能的解决方案(即表)的列表。
- 生成一个随机事实 f(例如:挪威人有一只猫)。
- 集合 T = S
- 从 T 中筛选出所有违反 f 的溶液。
- 如果 |T|= 0 然后转到 2(事实与前一个事实相矛盾)
- 如果 |T|<|S|然后设置 S = T 和 F.append(f)(事实尚未被先前的事实体现)
- 如果 |S|> 1 然后转到 2
完成后 - F 将是导致 S 中唯一剩余表的事实列表。
诚然,这是非常蛮力的,并且可能无法很好地处理 5X5 或更高的表。
有趣的是,"爱因斯坦"之谜(引用的意思是,一切"聪明"都倾向于分配给爱因斯坦,也许有更多的魅力),与数独生成算法(通过术语的正确翻译)以及魔方(3x3x3)求解算法有关
在数独的情况下,线索对应于网格上已经分配的数字,而缺失的信息对应于空插槽
在魔方的情况下(我觉得更有趣),线索对应于立方体的对称性(例如绿色紧挨着红色,就像那样)并且通过重新对齐(求解)立方体来找到缺失的数据
这是一个粗略的轮廓,谢谢
我认为Gareth Rees的答案的基础是合理的,但我认为加法方法而不是减法方法会更好。
你从一组完整的潜在线索(C),一组空的接受线索(D)和一个空的谜题解决方案(S)开始。
然后循环执行以下过程,直到 S 可行:
- 从C那里获取下一个线索(C i)。
- 通过尝试用 C i 解决难题来更新 S
- S 变了吗?如果是,将 C i 添加到 D;否则,请丢弃它。
- S 完整吗?如果是,您可以停止并使用 D 作为线索列表;否则,请从步骤 1 重复。
这将绝对保证没有不必要的线索,因为您只保留添加到谜题解决方案中的线索。这可能比从几十条(或几百条)线索开始,然后将它们减少到几条要快得多。(另请注意:通过一些调整,即使在 S 可以解决之后,您也可以通过添加额外的线索来轻松修改此过程以降低谜题难度。
这是另一个想法 - 一旦你生成了完整的网格,在手机上拍一张照片(或复制设计),然后在提供线索时删除项目。您可能会在任务进行到一半时忘记原始/最终布局的外观,并且可以避免误导您的受试者/应试者。
想为复活节做一个,类似的模式,5人,5种巧克力类型,5个年龄,5种不同的复活节帽子,5种不同的最喜欢的饮料,冰淇淋等。