2009-12-21 15 views
9

Der Verbrecher eine der Gruppen A, B, C und D.ein Logik-Puzzle lösen mit Prolog

A sagt, ist: "Es ist nicht mir"
B sagt: "Es ist D"
C sagt: „Es ist B“
D sagt: „Es ist nicht mir“

Und wir wissen, dass nur einer von ihnen die Wahrheit sagt.

Wer ist derjenige? Ich möchte es mit Prolog lösen.

Es ist eine Interviewfrage.

+0

Habe ich das Recht bekommen: ein Verbrecher ist, aber drei sind Lügner ?! – ThomasH

Antwort

23

Einzeiler Lösung

?- 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. 
+0

+1 Das ist interessant. – ThomasH

+0

Was ist, wenn die Kriminellen zwei von a, b, c, d sein können? – user198729

+0

@ user198729: Dann beende die Klausel mit A + B + C + D =: = 1, A + B + C + D =: = 2. –

17

Haftungsausschluss: Dies ist Xonix "Lösung. Wenn Sie es wünschen, wählen Sie ihn bis. Aber da ich ein bisschen kratzte, um herauszufinden, was vor sich ging, dachte ich, ich könnte meine Kommentare genauso gut anbieten, damit andere davon profitieren können.

Zuerst hier seine Lösung als eine richtige Klausel ist:

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. 

Und es geht so:

Zuerst er durch die Liste der Personen läuft (niedrigerer Fall sein, also sind sie keine Variablen). K wird nacheinander für jede von ihnen instanziiert.

Mit jedem möglichen Wert von K läuft er durch den Rest der Klausel. K kann als die Hypothese interpretiert wer der Verbrecher ist. Die nächsten 4 Zeilen sollen Bindings zu jeder der Variablen A, B, C und D liefern. Sie können sie so lesen: Unter der Annahme, dass a nicht der Verbrecher ist, ist eine Wahrheit ansonsten nicht wahr. Unter der Annahme, dass d der Verbrecher ist, ist b wahrheitsgemäß sonst nicht. Asf. Das heißt, die Variablen A, B, ... erfassen die Wahrhaftigkeit des entsprechenden Individuums bei einem bestimmten Kriminellen. Als bekannte Einschränkung ist die Tatsache, dass nur eine von ihnen wahrheitsgemäß ist, die Summe ihrer Wahrheitswerte muss 1 sein. Beim Zurückverfolgen macht Prolog die nächste Bindung für K und läuft erneut durch. Stellt sich heraus, die Einschränkung ist nur erfüllt, wenn a der Verbrecher ist (und d sagt die Wahrheit, wenn ich mich nicht irre). Niedlich.

8

Hier ist eine andere Lösung, die ich etwas weniger kryptisch als Xonix finde. Getestet in 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). 

Anwendungsbeispiel:

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

Ein ähnliches Problem und die entsprechende Lösung auch hier gefunden werden kann:

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

Wie die Lösung von Kaarel geschrieben, ist möglich, eine beantragen Begründung/Erklärung für die gefundene Lösung.

+0

Bitte geben Sie nicht [Link nur Antworten] (http://meta.stackoverflow.com/tags/link-only-answers/info), schreiben Sie etwas mehr. –

3

ich auf dieses Problem lief und wollte ihm einen Schuss geben:

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