Để giải quyết vấn đề với Prolog, như với bất kỳ ngôn ngữ lập trình nào, dù là khai báo hay bắt buộc, bạn phải suy nghĩ về cách trình bày giải pháp và đầu vào.
Vì đây là câu hỏi về lập trình, nên nó đã trở nên phổ biến trên StackOverflow.com nơi các lập trình viên giải quyết các vấn đề lập trình. Ở đây tôi sẽ cố gắng để khoa học hơn.
A t t e n d( X) → A t t e n d( Y) ∧ Một t t e n d( Z)A t t e n d( Một D ) ∧ Một t t e n d( B M) → A t t e n d( D D )
Daisy Dodderidge cho biết cô sẽ đến nếu cả Albus Dumbledore và Burdock Muldoon đều đến
khó điều trị hơn.
Với Prolog, cách tiếp cận đơn giản đầu tiên là tránh sự đảo ngược hoàn toàn mối quan hệ và thay vào đó là mục tiêu hướng đến.
Giả sử đặt hàng trong danh sách khách và sử dụng quy tắc
⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪A(X)∧A(Y)A(W)A(W)XY→A(Z),→A(X),→A(Y),<Z,<Z⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⊢A(W)→A(Z)
A(X)Attend(X)
Quy tắc này rất dễ thực hiện.
Một cách tiếp cận khá ngây thơ
Đối với khả năng đọc, hãy follows
là mối quan hệ được đưa ra làm đầu vào và brings
ngược lại.
Sau đó, đầu vào được đưa ra bởi
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]).
Và brings
có thể được định nghĩa như sau:
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
Nếu chúng ta xác định
partymaker(X):-Guests=[ad,bm,cp,dd,ec,fa],member(X,Guests),brings(X,Guests).
Chúng tôi nhận được các giải pháp độc đáo sau:
[ad,ec]
Đây không phải là danh sách đầy đủ, vì theo thứ tự chữ cái mệnh đề
follows(bm,[cp,dd]).
không hoạt động.
Một giải pháp khá liên quan đến câu đố gốc
Để giải quyết vấn đề hoàn toàn, bạn phải thực sự để hệ thống cố gắng chứng minh sự tham dự của những vị khách sau này mà không giới thiệu các vòng lặp vô hạn cho cây tìm kiếm. Có nhiều cách để thực hiện mục tiêu này. Mỗi cái đều có ưu điểm và nhược điểm.
Một cách là xác định lại brings/2
như sau:
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).
Đối số cuối cùng brings/4
là cần thiết để tránh một vòng lặp vô hạn trong try_bring
.
Điều này đưa ra các câu trả lời sau: Albus, Carlotta, Elfrida và Falco. Tuy nhiên, giải pháp này không phải là giải pháp hiệu quả nhất vì việc quay lui được giới thiệu mà đôi khi có thể tránh được.
Một giải pháp chung
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).
Bây giờ nếu ví dụ số liệu # 2 được đưa ra là
follows(fa,[dd,ec]).
follows(cp,[ad,bm]).
guests([ad,bm,cp,dd,ec,fa]).
Chúng tôi nhận được câu trả lời L = [[ad, bm, dd, ec]]. Điều đó có nghĩa là tất cả khách nhưng Carlotte và Falco phải được mời.
Các câu trả lời mà giải pháp này đưa ra cho tôi phù hợp với các giải pháp được đưa ra trong bài viết Phù thủy độc ác ngoại trừ tập dữ liệu số 6, nơi có nhiều giải pháp được sản xuất. Đây dường như là giải pháp chính xác.
Cuối cùng, tôi phải đề cập đến thư viện Prolog của CLP (FD) đặc biệt phù hợp với loại vấn đề này.
attend(BM) :- attend(AD).
chính xác giống nhưattend(X) :- attend(Y).