繁体   English   中英

使用Prolog解决逻辑难题

[英]Solving a logic puzzle using Prolog

罪犯是A,B,C和D之一。

A说:“不是我”
B说:“是D”
C说:“是B”
D说:“不是我”

我们知道,只有其中一个说实话。

谁是那个? 我想使用Prolog解决它。

这是一个面试问题。

一线解决方案

?- member(K,[a,b,c,d]),(K\=a->A=1;A=0),(K=d->B=1;B=0),(K=b->C=1;C=0),(K\=d->D=1;D=0),A+B+C+D=:=1.
K = a,
A = 0,
B = 0,
C = 0,
D = 1 ;
false.

免责声明 :这是Xonix的解决方案。 如果您喜欢,请投票给他 但是,由于我花了很多力气才想出正在发生的事情,我想我也可以发表自己的评论,以便其他人可以从中受益。

首先,这是他作为适当子句的解决方案:

criminal(K):-
    member(K,[a,b,c,d]),
    (K\=a -> A=1;A=0),
    (K=d  -> B=1;B=0),
    (K=b  -> C=1;C=0),
    (K\=d -> D=1;D=0),
    A+B+C+D=:=1.

它是这样的:

首先,他浏览了个人列表(必须为小写,因此它们不是变量)。 K依次实例化到他们每个人。

对于K每个可能值,他遍历该子句的其余部分。 K可以解释为罪犯是谁的假设。 接下来的4行将提供对变量A,B,C和D的绑定。您可以按以下方式阅读它们:在a不是罪犯的假设下,a是真实的,否则就不是。 d是罪犯的假设下,b是真实的,否则不是。 Asf。 即,变量A,B,...捕获了给定特定罪犯的相应个人的真实性。

一个已知的约束条件是,只有其中一个是真实的,它们的真实值之和必须为1。回溯时,Prolog对K进行下一个绑定,然后再次遍历。 事实证明,只有在a是罪犯的情况下才满足约束条件(如果我没记错的话, d是在说实话)。 可爱。

这是另一个解决方案,我发现它比Xonix的解决方案少一些神秘性。 在SWI-Prolog中测试。

% To find a criminal and the truthteller
% 1. Pick a possible criminal
% 2. Pick a possible truthteller and the remaining liars
% 3. Assert that the truthteller's statement is the truth
% 4. Assert that every liar's statement is not the truth
% If both the assertions succeed
% then we have found a criminal and the truthteller.
criminal_and_truthteller(Criminal, Truthteller) :-
    Group = [a, b, c, d],
    member(Criminal, Group),
    select(Truthteller, Group, Liars),
    statement(Truthteller, Criminal, Truth),
    Truth,
    forall(
        member(Liar, Liars),
        (statement(Liar, Criminal, Lie), \+ Lie)
    ).

% Statements
% Arg 1: Who says
% Arg 2: About whom
% Arg 3: Which statement
% e.g. "a claims that a is not a criminal"
statement(a, C, a \= C).
statement(b, C, d  = C).
statement(c, C, b  = C).
statement(d, C, d \= C).

用法示例:

?- criminal_and_truthteller(Criminal, Truthteller).
Criminal = a,
Truthteller = d ;
false.

我遇到了这个问题,想试一试:

a(K) :- K \== a.
b(d).
c(b).
d(K) :- K \== d.

solve(TruthTeller) :-
    member(K, [a, b, c, d]),
    xor([a(K), b(K), c(K), d(K)], Truth),
    Truth =.. [TruthTeller|_].

xor([Head|Tail], Result) :-
    (   call(Head)
     -> forall(member(X, Tail), \+ call(X)), Result = Head
     ;  xor(Tail, Result)).

在这里也可以找到类似的问题和相应的解决方案:

https://github.com/LogtalkDotOrg/logtalk3/blob/master/examples/puzzles/jam_thief.lgt

就像Kaarel发布的解决方案一样,可以为找到的解决方案要求理由/解释。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM