Prolog - 谜语的解答

问题描述 投票:0回答:2

我在互联网上发现了一个谜语,我想使用 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 的新手,仅此而已。

prolog
2个回答
2
投票

这是我写的

:- 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].

0
投票

替代方法:

:- 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.

...意味着孩子是女性。

© www.soinside.com 2019 - 2024. All rights reserved.