解决“谁拥有斑马”的问题 以编程方式?
编辑:这个谜题也被称为“爱因斯坦之谜”
谁拥有斑马(您可以< a href="https://www.brainzilla.com/logic/zebra/einsteins-riddle/" rel="noreferrer" title="Einstein's Riddle">在这里尝试在线版本)是一个示例这是一组经典的谜题,我敢打赌 Stack Overflow 上的大多数人都可以用笔和纸解决它。 但程序化解决方案会是什么样子呢?
根据下面列出的线索......
- 有五栋房子。
- 每栋房子都有自己独特的颜色。
- 所有房主都来自不同的国籍。
- 他们都有不同的宠物。
- 他们都喝不同的饮料。
- 他们都抽不同的香烟。
- 英国人住在红房子里。
- 瑞典人有一只狗。
- 丹麦人喝茶。
- 绿房子位于白宫的左侧。
- 他们在温室里喝咖啡。
- 抽 Pall Mall 烟的人养的是鸟。
- 在黄色的房子里,他们抽烟登喜路。
- 在中间的房子里,他们喝牛奶。
- 挪威人住在第一栋房子里。
- 抽 Blend 烟的男人住在养猫的房子旁边。
- 在他们养马的房子旁边的房子里,他们抽登喜路烟。
- 抽 Blue Master 烟的男人喝啤酒。
- 德国人抽Prince烟。
- 挪威人住在蓝房子旁边。
- 他们在抽 Blend 烟的房子旁边的房子里喝水。
...谁拥有斑马?
Edit: this puzzle is also known as "Einstein's Riddle"
The Who owns the Zebra (you can try the online version here) is an example of a classic set of puzzles and I bet that most people on Stack Overflow can solve it with pen and paper. But what would a programmatic solution look like?
Based on the clues listed below...
- There are five houses.
- Each house has its own unique color.
- All house owners are of different nationalities.
- They all have different pets.
- They all drink different drinks.
- They all smoke different cigarettes.
- The English man lives in the red house.
- The Swede has a dog.
- The Dane drinks tea.
- The green house is on the left side of the white house.
- They drink coffee in the green house.
- The man who smokes Pall Mall has birds.
- In the yellow house they smoke Dunhill.
- In the middle house they drink milk.
- The Norwegian lives in the first house.
- The man who smokes Blend lives in the house next to the house with cats.
- In the house next to the house where they have a horse, they smoke Dunhill.
- The man who smokes Blue Master drinks beer.
- The German smokes Prince.
- The Norwegian lives next to the blue house.
- They drink water in the house next to the house where they smoke Blend.
...who owns the Zebra?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
以下是基于约束编程的 Python 解决方案:
输出:
找到解决方案需要 0.6 秒(CPU 1.5GHz)。
答案是“德国人拥有斑马”。
要通过
pip
安装constraint
模块:pip install python-constraint
手动安装:
下载:
$ wget https://pypi.python.org/packages/source/p/python-constraint/python-constraint-1.2.tar.bz2#md5=d58de49c85992493db53fcb59b9a0a45
提取(Linux/Mac/BSD):
$ bzip2 -cd python-constraint-1.2.tar.bz2 | $ bzip2 -cd python-constraint-1.2.tar.bz2 | tar xvf -
提取(Windows,使用7zip):
> 7z e python-constraint-1.2.tar.bz2
> 7z e python-constraint-1.2.tar
安装:
$ cd python-constraint-1.2
$ python setup.py install
Here's a solution in Python based on constraint-programming:
Output:
It takes 0.6 seconds (CPU 1.5GHz) to find the solution.
The answer is "German owns zebra."
To install the
constraint
module viapip
:pip install python-constraint
To install manually:
download:
$ wget https://pypi.python.org/packages/source/p/python-constraint/python-constraint-1.2.tar.bz2#md5=d58de49c85992493db53fcb59b9a0a45
extract (Linux/Mac/BSD):
$ bzip2 -cd python-constraint-1.2.tar.bz2 | tar xvf -
extract (Windows, with 7zip):
> 7z e python-constraint-1.2.tar.bz2
> 7z e python-constraint-1.2.tar
install:
$ cd python-constraint-1.2
$ python setup.py install
在 Prolog 中,我们只需从中选择元素即可实例化域:)(为了提高效率,进行互斥选择)。 使用 SWI-Prolog,
可以立即运行:
In Prolog, we can instantiate the domain just by selecting elements from it :) (making mutually-exclusive choices, for efficiency). Using SWI-Prolog,
Runs quite instantly:
一位发帖者已经提到 Prolog 是一个潜在的解决方案。 这是真的,这就是我将使用的解决方案。 更一般地说,这对于自动推理系统来说是一个完美的问题。 Prolog 是形成这样一个系统的逻辑编程语言(以及相关的解释器)。 它基本上允许从使用一阶逻辑所做的陈述中得出事实结论。 FOL 基本上是命题逻辑的更高级形式。 如果您决定不想使用 Prolog,您可以使用您自己创建的类似系统,使用诸如 modus ponens 执行得出结论。
当然,您需要添加一些关于斑马的规则,因为它没有在任何地方提到...我相信其目的是您可以找出其他 4 只宠物,从而推断出最后一只是斑马? 您需要添加规则,规定斑马是宠物之一,并且每个房子只能养一只宠物。 将这种“常识”知识纳入推理系统是将该技术用作真正的人工智能的主要障碍。 有一些研究项目,例如 Cyc,正在尝试通过暴力来提供此类常识。 他们取得了巨大的成功。
One poster already mentioned that Prolog is a potential solution. This is true, and it's the solution I would use. In more general terms, this is a perfect problem for an automated inference system. Prolog is a logic programming language (and associated interpreter) that form such a system. It basically allows concluding of facts from statements made using First Order Logic. FOL is basically a more advanced form of propositional logic. If you decide you don't want to use Prolog, you could use a similar system of your own creation using a technique such as modus ponens to perform the draw the conclusions.
You will, of course, need to add some rules about zebras, since it isn't mentioned anywhere... I believe the intent is that you can figure out the other 4 pets and thus deduce the last one is the zebra? You'll want to add rules that state a zebra is one of the pets, and each house can only have one pet. Getting this kind of "common sense" knowledge into an inference system is the major hurdle to using the technique as a true AI. There are some research projects, such as Cyc, which are attempting to give such common knowledge through brute force. They've met with an interesting amount of success.
SWI-Prolog 兼容:
在解释器处:
SWI-Prolog compatible:
At the interpreter:
这就是我的做法。 首先,我会生成所有有序的 n 元组
5^6,即 15625 个,易于管理。 然后我会过滤掉简单的布尔条件。 有 10 个,您希望每个条件过滤掉 8/25 的条件(1/25 的条件包含有狗的瑞典人,16/25 的条件包含有非狗的非瑞典人) 。 当然,它们不是独立的,但在过滤掉这些之后,应该不会剩下多少了。
之后,你就得到了一个很好的图形问题。 创建一个图,其中每个节点代表剩余的 n 元组之一。 如果两端在某个 n 元组位置包含重复项或违反任何“位置”约束(其中有五个),则向图形添加边。 从这里开始,您就差不多到家了,在图表中搜索一组独立的五个节点(没有任何节点通过边连接)。 如果数量不是太多,您可能会详尽地生成 n 元组的所有 5 元组,然后再次过滤它们。
这可能是代码高尔夫的一个很好的候选者。 有人可能可以用像 haskell 这样的东西一行解决它:)
事后思考:初始过滤器传递还可以消除位置约束中的信息。 虽然不多(1/25),但仍然很重要。
Here's how I'd go about it. First I'd generate all the ordered n-tuples
5^6 of those, 15625, easily manageable. Then I'd filter out the simple boolean conditions. there's ten of them, and each of those you'd expect to filter out 8/25 of the conditions (1/25 of the conditions contain a Swede with a dog, 16/25 contain a non-Swede with a non-dog). Of course they're not independent but after filtering those out there shouldn't be many left.
After that, you've got a nice graph problem. Create a graph with each node representing one of the remaining n-tuples. Add edges to the graph if the two ends contain duplicates in some n-tuple position or violate any 'positional' constraints (there's five of those). From there you're almost home, search the graph for an independent set of five nodes (with none of the nodes connected by edges). If there's not too many, you could possibly just exhaustively generate all the 5-tuples of n-tuples and just filter them again.
This could be a good candidate for code golf. Someone can probably solve it in one line with something like haskell :)
afterthought: The initial filter pass can also eliminate information from the positional constraints. Not much (1/25), but still significant.
另一个Python解决方案,这次使用Python的PyKE(Python知识引擎)。 诚然,它比 @JFSebastian 的解决方案中使用 Python 的“约束”模块更冗长,但它为任何研究此类问题的原始知识引擎的人提供了一个有趣的比较。
clues.kfb
relations.krb
driver.py(实际上更大,但这就是本质)
示例输出:
来源:https://github.com/DreadPirateShawn/pyke-who-owns-zebra
Another Python solution, this time using Python's PyKE (Python Knowledge Engine). Granted, it's more verbose than using Python's "constraint" module in the solution by @J.F.Sebastian, but it provides an interesting comparison for anybody looking into a raw knowledge engine for this type of problem.
clues.kfb
relations.krb
driver.py (actually larger, but this is the essence)
Sample output:
Source: https://github.com/DreadPirateShawn/pyke-who-owns-zebra
以下是完整解决方案的摘录 使用 NSolver,发布于 C# 中的爱因斯坦之谜:
Here is an excerpt from the full solution using NSolver, posted at Einstein’s Riddle in C#:
ES6 (Javascript) 解决方案
,具有大量 ES6 生成器和一点lodash。 您将需要 Babel 来运行它。
结果:
对我来说,运行时间约为 2.5 秒,但是可以通过更改规则的顺序来大大改善。 为了清楚起见,我决定保留原始顺序。
谢谢,这是一个很酷的挑战!
ES6 (Javascript) solution
With lots of ES6 generators and a little bit of lodash. You will need Babel to run this.
Result:
Run time is around 2.5s for me, but this can be improved a lot by changing the order of rules. I decided to keep the original order for clarity.
Thanks, this was a cool challenge!
这是 CLP(FD) 中的一个简单解决方案(另请参见 clpfd< /a>):
运行它,会产生:
Here is a straightforward solution in CLP(FD) (see also clpfd):
Running it, produces:
在 PAIP(第 11 章)中,Norvig 使用 Lisp 中嵌入的 Prolog 解决了斑马谜题。
In PAIP (Chapter 11), Norvig solves the zebra puzzle using a Prolog embedded in Lisp.
这实际上是一个约束求解问题。 您可以使用类似逻辑编程的语言中的通用约束传播来实现这一点。 我们有一个专门针对 ALE(属性逻辑引擎)系统中的 Zebra 问题的演示:
http://www.cs.toronto.edu/~gpenn/ale.html
以下是简化斑马拼图编码的链接:
http://www.cs.toronto.edu/~gpenn/ale/files/grammars/baby.pl
至有效地做到这一点是另一回事。
This is really a constraint solving problem. You can do it with a generalized kind of constraint propagation in logic-programming like languages. We have a demo specifically for the Zebra problem in the ALE (attribute logic engine) system:
http://www.cs.toronto.edu/~gpenn/ale.html
Here's the link to the coding of a simplified Zebra puzzle:
http://www.cs.toronto.edu/~gpenn/ale/files/grammars/baby.pl
To do this efficiently is another matter.
以编程方式解决此类问题的最简单方法是对所有排列使用嵌套循环,并检查结果是否满足问题中的谓词。 许多谓词可以从内循环提升到外循环,以显着降低计算复杂性,直到可以在合理的时间内计算出答案。
源自 F# Journal 中的一篇文章:
下面是一个简单的 F# 解决方案, 9 毫秒是:
The easiest way to solve such problems programmatically is to use nested loops over all permutations and check to see if the result satisfies the predicates in the question. Many of the predicates can be hoisted from the inner loop to outer loops in order to dramatically reduce the computational complexity until the answer can be computed in a reasonable time.
Here is a simple F# solution derived from an article in the F# Journal:
The output obtained in 9ms is:
这是维基百科中定义的斑马拼图的 MiniZinc 解决方案:
解决方案:
This is a MiniZinc solution to the zebra puzzle as defined in Wikipedia:
Solution:
Microsoft Solver Foundation 示例来自:
https: //msdn.microsoft.com/en-us/library/ff525831%28v=vs.93%29.aspx?f=255&MSPPError=-2147217396
The Microsoft Solver Foundation example from:
https://msdn.microsoft.com/en-us/library/ff525831%28v=vs.93%29.aspx?f=255&MSPPError=-2147217396
可以在此处找到编程解决方案的一个示例(最初是为类似问题编写的):https ://puzzle-solvers.readthedocs.io/en/latest/
我实现了类之间的关系矩阵,它会在您输入约束时更新。 API 以
Solver
类,您可以使用类别和标签对其进行初始化。 然后,您可以调用诸如adjecent_to< 之类的方法/code>
和
match
来建立关系。这些文档对底层逻辑有相当详尽的解释。 您描述的确切难题是 演示之一。 为了回答你的字面问题,演示如下:
这段代码的好处是,它是人们可以在一夜之间编写的东西,而不是一个经过深思熟虑的生产包,但它仍然可以完成工作。
One example of a programmatic solution (originally written for a similar question), can be found here: https://puzzle-solvers.readthedocs.io/en/latest/
I implemented a matrix of relationships between the classes, which gets updated as you enter the constraints. The API centers on a
Solver
class, which you initialize with the categories and labels. You then call methods likeadjecent_to
andmatch
on to set up the relationships.The docs have a fairly thorough explanation of the underlying logic. The exact puzzle you describe is one of the demos. To answer your literal question, here is what the demo looks like:
The nice thing about this code is that it's something one might write overnight, and not a really well thought-out production package, yet it still does the job.