我在互联网上发现了一个谜语,我想使用 Prolog 来解决它。我有一个 Prolog 程序,但结果与我的逻辑方法不符,所以我对 Prolog 程序中缺少的内容感兴趣。任何帮助,将不胜感激。很抱歉发布到 stackoverflow,我找不到任何更适合解决此问题的 stackexchange 网站。
谜语正文:
丛林里住着一个土著部落,他们的表情有着一种非同寻常的古怪:男人总是说实话;女人从来不会连续说两个假句子,也不会连续说两个真句子。最令人不舒服的是,男性和女性的着装和外表大体上都是一样的,所以认识到真相有时会很复杂。一位人类学家试图研究母语,但他仍然不太懂母语。所以有一天,他遇到一个家庭,问一个孩子是不是男孩,人类学家不明白答案。这就是为什么他求助于父母,其中一位告诉他“孩子说他是男孩”,另一位则说“孩子是女孩,孩子撒谎了”。人类学家需要知道孩子如何反应(或撒谎),以继续研究当地传统以确定孩子和父母双方的性别。
我相信我的逻辑方法是正确的:
孩子可以是女人,也可以是男人。让他成为一个男人。然后他不得不说他是一个男人,因为男人总是说实话。家长2说孩子是女孩,孩子撒了谎。父母2肯定不是男人,因为孩子是男人就矛盾了。但父母不能是女性,因为只要一句话就一定是假的。但这并不是因为孩子是男孩,他当然没有撒谎。另外,孩子是一个男人,因此他不是一个女孩,因此这两句话都是不真实的。孩子肯定不是男人。让孩子成为女人。这让事情变得有点复杂,因为孩子可以说她是男人或女人。让孩子是女人,说她是男人。让我们从家长2开始。这一定是个男人,因为他说孩子是个女人,而且撒了谎。父母 1 可以是女性,因为她说婴儿说她是男孩。女人可能会说谎,也可能不会。如果我们承认一个孩子可以有两个父亲,那么这个孩子也可能是一个男人。为了控制,让孩子是女人,说她是女人。家长 2 一定是女性,因为她说孩子是个女孩,这是事实,但同时又说她在撒谎,这不是事实。那么父母1一定是一个男人,但这不能是因为男人总是说实话。但家长1说孩子说他是男孩,这不是事实。只有孩子的父母可以有两个妻子,这才有可能。解决方案:孩子是女性,父母 1 是女性,父母 2 是男性。
我的Prolog程序说这个问题有多种解决方案。第一个表示孩子是男性,父母 1 是男性。父母 2 是女性。正确的解法是第七个。我是否错过了一些“如果”或!某处的操作员?还是这种方法完全不好?
% split(+list, -listOfItemsAtEvenPositions, -listOfItemsAtOddPositions)
split([], [], []).
split([X|TList], Even, [X|TOdd]) :- rozdel(TList, TOdd, Even).
% says(+gender, +listOfSentences, -listOfTrueSentences)
% Men always say the truth.
says(man, X, X).
% Women never say two false sentences in sequence, or two true sentences in sequence.
says(woman, Sentences, TrueSentences) :-
split(Sentences, _, TrueSentences); % Every odd sentence says the truth.
split(Sentences, TrueSentences, _). % Every even sentence says the truth.
% solution(-genderOfChild, -genderOfFirstParent, -genderOfSecondParent)
solution(Child, Parent1, Parent2) :-
% The child said something.
says(Child, _, _),
% The first parent says: "The child said he was a boy"
says(Parent1, [says(Child, [Child=man], _)], _),
% The second parent says: "The child is a girl, the child lied."
says(Parent2, [Child=woman, says(Child, [Child=man], _)], _),
% The child cannot have two parents of same gender.
Parent1 \= Parent2.
我是 Prolog 的新手,仅此而已。
这是我写的
:- use_module(library(clpb)).
solve(L) :-
L = [A,B,C,D],
% A : true means the child is a boy
% B : true means the child tells the truth
% C : true means person 1 is a man
% D : true means person 2 is a man
% person 1 : The child said he was a boy (and a man tells the truth)
% if person 1 is a man
sat(C =< A),
% if person 1 is a woman, we can't write anything
% because there's only one sentence
% person 2 "The child is a girl, the child lied"
% if person 2 is a man
sat(D =< ~A * ~B),
% if person 2 is a woman
sat(~D =< ((~A # B) # (A # ~B))),
% Prolog works
labeling([A,B,C,D]).
我明白了:
?- solve(L).
L = [0, 0, 0, 1].
这意味着孩子是女孩,她也撒谎了,也是人1。第二个人是个男人。
请注意,可以忽略第 1 个人:
:- use_module(library(clpb)).
solve(L) :-
L = [A,B,C],
% A : true means the child is a boy
% B : true means the child tells the truth
% C : true means person 2 is a man
% person 2 "The child is a girl, the child lied"
% if person 2 is a man
sat(C =< ~A * ~B),
% if person 2 is a woman
sat(~C =< ((~A # B) # (A # ~B))),
% Prolog works
labeling([A,B,C]).
答案:
?- solve(L).
L = [0, 0, 1].
替代方法:
:- use_module(library(clpb)).
male_statements(IsMale, Statements) :-
length(Statements, Len),
% Males tell the truth
( Len = 1
-> sat((IsMale * card([Len], Statements)) # ~IsMale)
% With 2 statements, females tell the truth exactly once
; sat((IsMale * card([Len], Statements)) # (~IsMale * card([1], Statements)))
).
is_boy(IsBoy) :-
% Family: the parents are male & female
sat(P1Man # P2Man),
male_statements(P1Man, [IsBoy]),
% "The child lied" means the child must be female
male_statements(P2Man, [~IsBoy, ~IsBoy]).
swi-prolog 的结果:
?- is_boy(Male).
Male = 0.
...意味着孩子是女性。