프로그래밍 언어와 마찬가지로 Prolog로 문제를 해결하려면 선언적이거나 명령적인 솔루션과 입력의 표현에 대해 생각해야합니다.
이것은 프로그래밍 질문이므로 프로그래머가 프로그래밍 문제를 해결하는 StackOverflow.com에서 인기가있었습니다. 나는 더 과학적이 되려고 노력할 것이다.
OP의 문제를 해결하려면 입력에 명시된 종속성에 의해 정의 된 관계를 역전시켜야합니다. 폼의 절 t t E N D ( X ) → t t 즉 n 개의 D ( Y ) ∧ t t E N D ( Z ) 역방향 쉽다. 조항 A t t e n d ( A D ) ∧ A t t e n d (Attend(X)→Attend(Y)∧Attend(Z) 등A t t end( A D ) ∧ A t t end(BM) → A t t end( D D )
Daisy Dodderidge는 Albus Dumbledore와 Burdock Muldoon이 모두 오면 그녀가 올 것이라고 말했다
치료하기가 더 어렵습니다.
Prolog를 사용하는 첫 번째 간단한 방법은 관계의 완전한 반전을 피하고 대신 목표를 지시하는 것입니다.
손님 목록에 주문을 가정하고 규칙을 사용하십시오.
⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪A ( X) ∧ A ( Y)A ( W)A ( W)엑스와이→ A ( Z) ,→ A ( X) ,→ A ( Y) ,< Z,< Z⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⊢A ( W) → A ( Z)
(우리가 사용 ( X ) 대신 t를 t의 E N D ( X는 ) 짧아야하는)A ( X)A t t e 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)
엑스
우리가 정의하면
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→ V'
에스⊆ 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를 제외한 모든 손님을 초대해야 함을 의미합니다.
이 솔루션이 제공 한 답변은 더 많은 솔루션이 생성 된 데이터 세트 # 6을 제외하고 Wicked Witch 기사에 제공된 솔루션과 일치합니다. 이것은 올바른 해결책 인 것 같습니다.
마지막으로 이런 종류의 문제에 특히 적합한 Prolog의 CLP (FD) 라이브러리를 언급해야합니다.
attend(BM) :- attend(AD).
입니다.attend(X) :- attend(Y).