2009-12-21 10 views
9

Il criminale è uno di A, B, C e D.Risolvere un puzzle di logica utilizzando Prolog

A dice: "Non è me"
B dice: "E 'D"
C dice: "E 'B"
D dice: "non sono io"

e sappiamo che solo uno di loro dice la verità.

Chi è quello? Voglio risolverlo usando Prolog.

È una domanda di intervista.

+0

ho ricevuto tale diritto: uno è un criminale, ma tre sono bugiardi ?! – ThomasH

risposta

23

soluzione One-liner

?- 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 Questo è interessante. – ThomasH

+0

Cosa succede se i criminali possono essere due di a, b, c, d? – user198729

+0

@ user198729: Quindi terminare la clausola con A + B + C + D =: = 1; A + B + C + D =: = 2. –

17

responsabilità: Questo è Xonix 'soluzione. Se ti piace vota lui su. Ma siccome mi è costato un po 'di grattacapi per capire cosa stava succedendo, ho pensato che avrei potuto anche offrire i miei commenti in modo che altri potessero trarne beneficio.

In un primo momento, ecco la sua soluzione come clausola corretta:

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. 

E va in questo modo:

In un primo momento, si attraversa l'elenco delle persone (devono essere minuscolo, quindi non sono variabili). K viene istanziato a ciascuno di essi a turno.

Con ogni possibile valore di K, viene eseguito il resto della clausola. K può essere interpretato come l'ipotesi di chi è il criminale. Le 4 linee successive sono per fornire associazioni a ciascuna delle variabili A, B, C e D. Puoi leggerle così: Partendo dal presupposto che a non è il criminale, a è vero altrimenti no. Partendo dal presupposto che d è il criminale, b è vero altrimenti no. Asf. Cioè, le variabili A, B, ... catturano la veridicità dell'individuo corrispondente, dato un criminale specifico.

Come un vincolo noto è il fatto che solo uno di essi è veritiero, la somma dei loro valori di verità deve essere 1. In retrocessione, Prolog effettua il successivo legame per K, e lo attraversa di nuovo. Risulta che il vincolo è soddisfatto solo se a è il criminale (e d sta dicendo la verità, se non mi sbaglio). Carina.

8

Ecco un'altra soluzione che trovo un po 'meno criptica di quella di Xonix. Testato in SWI-Prolog. esempio

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

utilizzati:

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

Un problema simile e corrispondente soluzione può anche essere trovato qui:

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

Come la soluzione inviato da Kaarel, è possibile richiedere una giustificazione/spiegazione per la soluzione trovata.

+0

Si prega di non fornire [solo risposte di collegamento] (http://meta.stackoverflow.com/tags/link-only-answers/info), scrivere qualcosa di più. –

3

mi sono imbattuto in questo problema e ha voluto dare un colpo:

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