Untuk memecahkan masalah dengan Prolog, seperti halnya bahasa pemrograman apa pun, baik itu deklaratif atau imperatif, Anda harus memikirkan representasi solusi dan input.
Karena ini adalah pertanyaan pemrograman, itu akan populer di StackOverflow.com di mana programmer memecahkan masalah pemrograman. Di sini saya berusaha menjadi lebih ilmiah.
Untuk memecahkan masalah dalam OP, seseorang harus membalikkan hubungan yang ditentukan oleh dependensi yang dinyatakan dalam input. Klausul bentuk mudah untuk membalikkan. Klausul Sebuah t t e n d ( A D ) ∧ A t t e n d (A t t e nd( X) → A t t e n d( Y) ∧ A t t e n d( Z) sepertiA 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 mengatakan dia akan datang jika Albus Dumbledore dan Burdock Muldoon keduanya datang
lebih sulit diobati.
Dengan Prolog pendekatan sederhana pertama adalah untuk menghindari pembalikan penuh dari hubungan dan diarahkan sebagai tujuan.
Asumsikan pemesanan pada daftar tamu dan gunakan aturan
⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪A ( X) ∧ A ( Y)A ( W)A ( W)XY→ A ( Z) ,→ A ( X) ,→ A ( Y) ,< Z,< Z⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⊢A ( W) → A ( Z)
(Kami menggunakan alih-alih A t t e n d ( X ) untuk membuatnya singkat)A ( X)A t t e n d( X)
Aturan ini mudah diterapkan.
Pendekatan yang agak naif
Untuk keterbacaan, biarkan follows
hubungan diberikan sebagai input, dan brings
kebalikannya.
Kemudian input diberikan oleh
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]).
Dan brings
dapat didefinisikan sebagai berikut:
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
Jika kita mendefinisikan
partymaker(X):-Guests=[ad,bm,cp,dd,ec,fa],member(X,Guests),brings(X,Guests).
Kami mendapatkan solusi unik berikut:
[ad,ec]
Ini bukan daftar lengkap, karena menurut abjad memesan klausa
follows(bm,[cp,dd]).
tidak bekerja.
Solusi yang agak terlibat untuk teka-teki asli
Untuk menyelesaikan masalah sepenuhnya Anda harus benar-benar membiarkan sistem mencoba membuktikan kehadiran untuk tamu kemudian tanpa memperkenalkan loop tak terbatas ke pohon pencarian. Ada banyak cara untuk mencapai tujuan ini. Masing masing punya kelebihan dan kekurangan.
Salah satu caranya adalah mendefinisikan ulang brings/2
sebagai berikut:
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).
Argumen terakhir brings/4
diperlukan untuk menghindari infinite loop in try_bring
.
Ini memberikan jawaban berikut: Albus, Carlotta, Elfrida dan Falco. Namun solusi ini bukan yang paling efisien karena backtracking diperkenalkan di mana kadang-kadang dapat dihindari.
Solusi umum
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).
Sekarang jika misalnya dataset # 2 diberikan sebagai
follows(fa,[dd,ec]).
follows(cp,[ad,bm]).
guests([ad,bm,cp,dd,ec,fa]).
Kami mendapatkan jawaban L = [[iklan, bm, dd, ec]]. Yang berarti semua tamu kecuali Carlotte dan Falco harus diundang.
Jawaban solusi ini memberi saya cocok dengan solusi yang diberikan dalam artikel Penyihir Jahat dengan pengecualian dataset # 6, di mana lebih banyak solusi dihasilkan. Ini tampaknya menjadi solusi yang tepat.
Akhirnya, saya harus menyebutkan perpustakaan Prolog CLP (FD) yang sangat cocok untuk masalah seperti ini.
attend(BM) :- attend(AD).
persis sama denganattend(X) :- attend(Y).