Um ein Problem mit Prolog zu lösen, müssen Sie wie bei jeder Programmiersprache, sei es deklarativ oder imperativ, über die Darstellung der Lösung und die Eingabe nachdenken.
Da es sich um eine Programmierfrage handelt, wäre sie auf StackOverflow.com beliebt gewesen, wo Programmierer Programmierprobleme lösen. Hier würde ich versuchen, wissenschaftlicher zu sein.
Um das Problem im OP zu lösen, muss die Beziehung umgekehrt werden, die durch die in der Eingabe angegebenen Abhängigkeiten definiert ist. Sätze der Form sind leicht umzukehren. Die Klauseln A t t e n d ( A D ) ∧ A t t e n d (A t t e n d( X) → A t t e n d( Y) ∧ A t t e n d( Z) mögenA t t e n d( A D ) ∧ A t t e n d( B M) → A t t e n d( D D )
Daisy Dodderidge sagte, sie würde kommen, wenn sowohl Albus Dumbledore als auch Burdock Muldoon kämen
sind schwieriger zu behandeln.
Bei Prolog besteht der erste einfache Ansatz darin, eine vollständige Umkehrung der Beziehung zu vermeiden und stattdessen zielgerichtet zu sein.
Nehmen Sie eine Reihenfolge in der Gästeliste an und verwenden Sie eine Regel
⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪A ( X) ∧ A ( Y)A ( W)A ( W)XY.→ A ( Z) ,→ A ( X) ,→ A ( Y) ,< Z,< Z⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⊢A ( W) → A ( Z)
(Wir verwenden anstelle von A t t e n d ( X ) , um es kurz zu halten.)A ( X)A t t e n d( X)
Diese Regel ist einfach zu implementieren.
Ein eher naiver Ansatz
Zur besseren Lesbarkeit sei follows
die Beziehung als Eingabe angegeben und brings
umgekehrt.
Dann ist die Eingabe durch gegeben
follows(bm,[ad]).
follows(cp,[ad]).
follows(ad,[cp]).
follows(dd,[cp]).
follows(ad,[ec]).
follows(bm,[ec]).
follows(cp,[ec]).
follows(cp,[fa]).
follows(dd,[fa]).
follows(bm,[cp,dd]).
follows(ec,[cp,dd]).
follows(fa,[cp,dd]).
follows(dd,[ad,bm]).
Und brings
kann wie folgt definiert werden:
brings(X,S):-brings(X,S,[]).
brings(_X,[],_S).
brings(X,[X|L],S):-brings(X,L,[X|S]).
brings(X,[Y|L],S):-follows(Y,[X]),brings(X,L,[Y|S]).
brings(X,[Y|L],S):-follows(Y,[A,B]),
member(A,S),member(B,S),brings(X,L,[Y|S]).
brings/3(X,L,S)
X
Wenn wir definieren
partymaker(X):-Guests=[ad,bm,cp,dd,ec,fa],member(X,Guests),brings(X,Guests).
Wir erhalten die folgenden einzigartigen Lösungen:
[ad,ec]
Dies ist nicht die vollständige Liste, da unter der alphabetischen Reihenfolge die Klausel
follows(bm,[cp,dd]).
funktioniert nicht.
Eine ziemlich komplizierte Lösung für das ursprüngliche Rätsel
Um das Problem vollständig zu lösen, muss das System versuchen, die Anwesenheit späterer Gäste nachzuweisen, ohne Endlosschleifen in den Suchbaum einzufügen. Es gibt mehrere Möglichkeiten, um dieses Ziel zu erreichen. Jeder hat seine Vor- und Nachteile.
Eine Möglichkeit ist die brings/2
folgende Neudefinition :
brings(X,S):-brings(X,S,[],[]).
% brings(X,RemainsToBring,AlreadyTaken,AlreadyTried).
%
% Problem solved
brings(_X,[],_S,_N).
% Self
brings(X,[X|L],S,N):-brings(X,L,[X|S],N).
% Follower
brings(X,[Y|L],S,N):-follows(Y,[X]),brings(X,L,[Y|S],N).
% Y is not a follower, but X can bring 2
brings(X,[Y|L],S,N):- \+member(Y,N),\+follows(Y,[X]),
follows(Y,[A,B]),
try_bring(X,A,L,S,[Y|N]),
try_bring(X,B,L,S,[Y|N]),brings(X,L,[Y|S],N).
% Y is not a follower, but X can bring 1
brings(X,[Y|L],S,N):- \+member(Y,N),\+follows(Y,[X]),\+follows(Y,[_A,_B]),
follows(Y,[C]),
try_bring(X,C,L,S,[Y|N]),brings(X,L,[Y|S],N).
try_bring(_X,A,_L,S,_N):-member(A,S).
try_bring(X,A,L,S,N):- \+member(A,S),sort([A|L],Y),brings(X,Y,S,N).
Das letzte Argument in brings/4
ist notwendig, um eine Endlosschleife in zu vermeiden try_bring
.
Dies gibt die folgenden Antworten: Albus, Carlotta, Elfrida und Falco. Diese Lösung ist jedoch nicht die effizienteste, da das Zurückverfolgen dort eingeführt wird, wo es manchmal vermieden werden kann.
Eine allgemeine Lösung
r ( X, S) : V→ V′
S⊆ VV′= V∪ { X}
VUV
add_element(X,V,U):- ( var(V) -> % set difference that works in both modes
member(X,U),subtract(U,[X],V);
\+member(X,V),sort([X|V],U) ).
support(V,U):- guests(G), % rule application
member(X,G),
add_element(X,V,U),
follows(X,S),
subset(S,V).
set_support(U,V):- support(V1,U), % sort of a minimal set
( support(_V2,V1) ->
set_support(V1,V) ;
V = V1).
is_duplicate(X,[Y|L]):- ( subset(Y,X) ; is_duplicate(X,L) ).
% purging solutions that are not truly minimal
minimal_support(U,L):-minimal_support(U,[],L).
minimal_support([],L,L).
minimal_support([X|L],L1,L2):-( append(L,L1,U),is_duplicate(X,U) ->
minimal_support(L,L1,L2);
minimal_support(L,[X|L1],L2) ).
solution(L):- guests(G),setof(X,set_support(G,X),S),
minimal_support(S,L).
Nun, wenn zum Beispiel Datensatz # 2 als gegeben ist
follows(fa,[dd,ec]).
follows(cp,[ad,bm]).
guests([ad,bm,cp,dd,ec,fa]).
Wir erhalten die Antwort L = [[ad, bm, dd, ec]]. Das bedeutet, dass alle Gäste außer Carlotte und Falco eingeladen werden müssen.
Die Antworten, die diese Lösung mir gab, stimmten mit den im Wicked Witch-Artikel angegebenen Lösungen überein, mit Ausnahme des Datensatzes Nr. 6, in dem mehr Lösungen hergestellt wurden. Dies scheint die richtige Lösung zu sein.
Abschließend muss ich die CLP (FD) -Bibliothek von Prolog erwähnen, die für diese Art von Problemen besonders geeignet ist.
attend(BM) :- attend(AD).
ist es genau dasselbe wieattend(X) :- attend(Y).