ในการแก้ปัญหาด้วย Prolog เช่นเดียวกับภาษาการเขียนโปรแกรมใด ๆ ไม่ว่าจะเป็นการประกาศหรือจำเป็นคุณต้องคิดถึงการเป็นตัวแทนของการแก้ปัญหาและการป้อนข้อมูล
เนื่องจากนี่เป็นคำถามการเขียนโปรแกรมจึงเป็นที่นิยมใน StackOverflow.com ที่โปรแกรมเมอร์แก้ปัญหาการเขียนโปรแกรม ที่นี่ฉันจะพยายามเป็นวิทยาศาสตร์มากขึ้น
ในการแก้ปัญหาใน OP หนึ่งจะต้องย้อนกลับความสัมพันธ์ที่กำหนดโดยการอ้างอิงที่ระบุไว้ในอินพุต ข้อของแบบฟอร์มทีทีอีn d ( X ) → ทีทีอีn d ( Y ) ∧ ทีทีอีn d ( Z )เป็นเรื่องง่ายที่จะย้อนกลับ ข้อทีทีอีn d ( D ) ∧ ทีทีอีn d (ทีทีอีnd(X) → ทีทีอีnd(Y) ∧ ทีทีอีnd(Z)เช่นทีทีอีnd( A D ) ∧ A t t e nd( ขM) → ทีทีอีnd( D D )
เดซี่โดเดริดจ์บอกว่าเธอจะมาถ้าอัลบัสดัมเบิลดอร์และหญ้าเจ้าชู้ Muldoon มาทั้งคู่
ยากต่อการรักษา
ด้วย Prolog วิธีการง่าย ๆ แรกคือการหลีกเลี่ยงการย้อนกลับของความสัมพันธ์และเป้าหมายโดยตรงแทน
สมมติว่ามีการสั่งซื้อในรายชื่อแขกและใช้กฎ
⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪A (X) ∧ A ( Y)A (W.)A (W.)XY→ A ( Z) ,→ A ( X) ,→ A ( Y) ,< Z,< Z⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⊢A ( W.) → A ( Z)
(เราใช้( X )แทนทีทีอีn d ( X )ที่จะให้มันสั้น)A ( X)ทีทีอีn d( X)
กฎนี้ใช้งานง่าย
วิธีการที่ค่อนข้างไร้เดียงสา
สำหรับการอ่านให้follows
เป็นความสัมพันธ์ที่กำหนดเป็นอินพุตและbrings
เป็นสิ่งที่ตรงกันข้าม
จากนั้นอินพุตจะถูกกำหนดโดย
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]).
และbrings
สามารถกำหนดได้ดังนี้
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
ถ้าเรากำหนด
partymaker(X):-Guests=[ad,bm,cp,dd,ec,fa],member(X,Guests),brings(X,Guests).
เราได้รับโซลูชั่นที่เป็นเอกลักษณ์ดังต่อไปนี้:
[ad,ec]
นี่ไม่ใช่รายการที่สมบูรณ์เนื่องจากเรียงตามลำดับตัวอักษรตามตัวอักษร
follows(bm,[cp,dd]).
ไม่ทำงาน.
วิธีแก้ปัญหาที่ค่อนข้างเกี่ยวข้องกับตัวต่อดั้งเดิม
ในการแก้ปัญหาอย่างสมบูรณ์คุณต้องให้ระบบพยายามพิสูจน์การเข้าร่วมของแขกผู้เข้าพักในภายหลังโดยไม่ต้องวนซ้ำไม่ จำกัด กับแผนผังการค้นหา มีหลายวิธีในการบรรลุเป้าหมายนี้ แต่ละคนมีข้อดีและข้อเสีย
วิธีหนึ่งคือการกำหนดใหม่brings/2
ดังนี้:
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).
อาร์กิวเมนต์สุดท้ายในเป็นสิ่งจำเป็นเพื่อหลีกเลี่ยงการอยู่ในวงbrings/4
จำกัดtry_bring
นี่จะให้คำตอบต่อไปนี้: Albus, Carlotta, Elfrida และ Falco อย่างไรก็ตามวิธีนี้ไม่ใช่วิธีที่มีประสิทธิภาพมากที่สุดเนื่องจากมีการแนะนำการย้อนรอยซึ่งบางครั้งสามารถหลีกเลี่ยงได้
วิธีแก้ปัญหาทั่วไป
r ( X, S) : V→ โวลต์'
S⊆ VV'= V∪ { X}
VยูV
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).
ตอนนี้ถ้าได้รับชุดข้อมูลอินสแตนซ์ # 2 เป็น
follows(fa,[dd,ec]).
follows(cp,[ad,bm]).
guests([ad,bm,cp,dd,ec,fa]).
เราได้คำตอบ L = [[ad, bm, dd, ec]] ซึ่งหมายความว่าแขกทุกคน แต่ Carlotte และ Falco จะต้องได้รับเชิญ
คำตอบของวิธีแก้ปัญหานี้ให้ฉันตรงกับคำตอบในบทความ Wicked Witch ยกเว้นชุดข้อมูล # 6 ซึ่งมีวิธีแก้ไขเพิ่มเติม นี่น่าจะเป็นทางออกที่ถูกต้อง
ในที่สุดฉันต้องพูดถึงห้องสมุด CLP (FD) ของ Prolog ที่เหมาะสมเป็นพิเศษสำหรับปัญหาประเภทนี้
attend(BM) :- attend(AD).
เหมือนกับattend(X) :- attend(Y).