Чтобы решить проблему с Прологом, как и с любым языком программирования, будь то декларативный или императивный, вам нужно подумать о представлении решения и входных данных.
Поскольку это вопрос программирования, он был бы популярен на StackOverflow.com, где программисты решают задачи программирования. Здесь я бы попытался быть более научным.
Чтобы решить проблему в OP, необходимо изменить отношение, определенное зависимостями, указанными во входных данных. Пункты вида т т е л д ( Х ) → т т е н д ( У ) ∧ т т е н д ( Z ) легко обратное. Пункты A t t e n d ( A D ) ∧ A t t e n d (Т т е н д( X) → т т е н д( Y) ∧ т т е н д( Z) какТ т е н д( Д ) ∧ т т е н д( Б М) → т т е н д( Д Д )
Дейзи Доддридж сказала, что придет, если Альбус Дамблдор и Бердок Малдун придут
сложнее лечить.
С Прологом первый простой подход состоит в том, чтобы избежать полного изменения отношений и быть направленным на достижение цели.
Принять порядок в списке гостей и использовать правило
⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪А ( Х) ∧ A ( Y)А ( Ш)А ( Ш)ИксY→ A ( Z) ,→ A ( X) ,→ A ( Y) ,< Z,< Z⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⊢А ( Ш) → A ( Z)
(Мы используем вместо A t t e n d ( X ), чтобы сократить его)А ( Х)Т т е н д( 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
.
Это дает следующие ответы: Альбус, Карлотта, Эльфрида и Фалько. Однако это решение не является самым эффективным, поскольку вводится обратный путь, где его иногда можно избежать.
Общее решение
г ( х, S) : V→ V'
S⊆ VВ'= V∪ { Х}
ВUВ
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]]. Это означает, что все гости, кроме Карлотты и Фалько, должны быть приглашены.
Ответы, которые дало мне это решение, совпали с решениями, приведенными в статье Wicked Witch, за исключением набора данных № 6, где было создано больше решений. Кажется, это правильное решение.
Наконец, я должен упомянуть CLP (FD) библиотеку Prolog, которая особенно подходит для такого рода проблем.
attend(BM) :- attend(AD).
точно так же, какattend(X) :- attend(Y).