Как-то раз случай свел в купе известного астронома, поэта, прозаика и драматурга. Это были Алексеев, Борисов, Константинов и Дмитриев. Оказалось, что каждый из них взял с собой книгу, написанную одним из пассажиров этого купе. Алексеев и Борисов углубились в чтение, предварительно обменявшись купленными книгами. Поэт читал пьесу. Прозаик, очень молодой человек, выпустивший свою первую книгу, говорил, что он никогда ничего не читает по астрономии. Борисов купил в дорогу одно из произведений Дмитриева. Никто из пассажиров не покупал и не читал книги. Написанные им самим. Что читал каждый из них? Кто кем был?
Код Visual Prolog:
/*
147 Пассажиры - книголюбы
% Как-то раз случай свел в одном купе известного историка, поэта, прозаика и драматурга.
% Это были Алексеев, Борисов, Константинов и Дмитриев.
% Оказалось, что каждый из них взял с собой книгу, написанную одним из пассажиров.
% Алексеев и Борисов, дочитав каждый свою книгу, условились на завтра обменяться ими.
% Поэт читал пьесу.
% Прозаик, очень молодой человек, выпустивший свою первую книгу, говорил, что он в жизни не читал и не читает ничего по истории.
% Борисов купил произведение Дмитриева.
% Никто из пассажиров не покупал и не читал книгу, написанную им самим.
Что читал каждый из них?
Кто кем был?
*/
CONSTANTS
tab = " " % константа для отступов при выводе результатов
Domains
жанрКниги, жанрПисателя = symbol
фамилияПисателя = symbol
возможныеФамилии = фамилияПисателя*
пассажир = книголюб(фамилияПисателя,жанрПисателя,списокКниг)
списокПассажиров = пассажир*
списокСписковПассажиров = списокПассажиров*
книга = книга(фамилияПисателя,жанрКниги)
списокКниг = книга*
predicates
nondeterm возможнаяФамилия(фамилияПисателя)
nondeterm пишетВЖанре(жанрПисателя,жанрКниги)
nondeterm списокПассажировИКниг(списокПассажиров,списокКниг)
nondeterm одинИз(списокПассажиров,списокСписковПассажиров)
nondeterm одинИз(пассажир,списокПассажиров)
nondeterm одинИз(книга,списокКниг)
nondeterm читал(пассажир,книга)
nondeterm взялССобой(пассажир,книга)
nondeterm ищемРешение(списокПассажиров)
% формирование уникального списка решений и форматный вывод в окно программы
nondeterm уникальные_решения(списокСписковПассажиров,списокСписковПассажиров,списокСписковПассажиров)
nondeterm списокРешений(списокСписковПассажиров)
nondeterm выводРешений()
nondeterm выводРешений(списокСписковПассажиров)
nondeterm печатьРешенияКтоЧтоЧитал(списокПассажиров)
nondeterm печатьРешенияКтоКемБыл(списокПассажиров)
CLAUSES
одинИз(Х,[Первый|Хвост]):- Х=Первый; одинИз(Х,Хвост).
% Как-то раз случай свел в одном купе известного историка, поэта, прозаика и драматурга.
пишетВЖанре(историк,история).
пишетВЖанре(поэт,стихи).
пишетВЖанре(прозаик,проза).
пишетВЖанре(драматург,пьеса).
% Это были Алексеев, Борисов, Константинов и Дмитриев.
возможнаяФамилия(алексеев).
возможнаяФамилия(борисов).
возможнаяФамилия(константинов).
возможнаяФамилия(дмитриев).
списокПассажировИКниг(Пассажиры,Книги):-
% генерируем различные уникальные жанры
пишетВЖанре(ЖанрПисателя1,_),пишетВЖанре(ЖанрПисателя2,_),пишетВЖанре(ЖанрПисателя3,_),пишетВЖанре(ЖанрПисателя4,_),
% уникальность жанров
not(ЖанрПисателя1=ЖанрПисателя2),
not(ЖанрПисателя1=ЖанрПисателя3),not(ЖанрПисателя2=ЖанрПисателя3),
not(ЖанрПисателя1=ЖанрПисателя4),not(ЖанрПисателя2=ЖанрПисателя4),not(ЖанрПисателя3=ЖанрПисателя4),
% список пассажиров, с различными комбинациями жанров
Алексеев = книголюб(алексеев, ЖанрПисателя1 ,[_,_]),
Борисов = книголюб(борисов, ЖанрПисателя2 ,[_,_]),
Константинов = книголюб(константинов,ЖанрПисателя3 ,[_]),
Дмитриев = книголюб(дмитриев, ЖанрПисателя4 ,[_]),
% упорядоченный список пассажиров
Пассажиры=[Алексеев,Борисов,Константинов,Дмитриев],
% соответствие жанров
пишетВЖанре(ЖанрПисателя1,ЖанрКниги1),
пишетВЖанре(ЖанрПисателя2,ЖанрКниги2),
пишетВЖанре(ЖанрПисателя3,ЖанрКниги3),
пишетВЖанре(ЖанрПисателя4,ЖанрКниги4),
% жанр писател должен соответствовать жанру написанной им книги
К1 = книга(алексеев, ЖанрКниги1),
К2 = книга(борисов, ЖанрКниги2),
К3 = книга(константинов,ЖанрКниги3),
К4 = книга(дмитриев, ЖанрКниги4),
% упорядоченный список книг
Книги = [К1,К2,К3,К4].
% сопоставляет Книгу с однойИз ПрочитанныхКниг Пассажира
читал(Пассажир,Книга):-
Пассажир=книголюб(_,_,ПрочитанныеКниги),
одинИз(Книга,ПрочитанныеКниги).
взялССобой(Пассажир,Книга):-
Пассажир = книголюб(_,_,[Книга|_]),
читал(Пассажир,Книга).
ищемРешение(Пассажиры):-
% Как-то раз случай свел в одном купе известного историка, поэта, прозаика и драматурга.
% Это были Алексеев, Борисов, Константинов и Дмитриев.
% ГИПОТЕЗА %
% формируются упорядоченные списки, где у пассажиров указана фамилия и жанр (список прочитанных книг неопределён [_] или [_,_])
% отдельно формируется список книг, написанных этими писателями
списокПассажировИКниг(Пассажиры,Книги),
одинИз(Алексеев,Пассажиры),
одинИз(Борисов,Пассажиры),
одинИз(Константинов,Пассажиры),
одинИз(Дмитриев,Пассажиры),
Поэт = книголюб(_,поэт,_), одинИз(Поэт,Пассажиры),
Прозаик = книголюб(_,прозаик,_),одинИз(Прозаик,Пассажиры),
% Оказалось, что каждый из них взял с собой книгу, написанную одним из пассажиров.
% Проверка на уникальность книг. Необходима здесь, т.к.
% именно здесь мы говорим, что каждый пассажир
% читал однуИз книг, написанных другими пассажирами
одинИз(К1,Книги),
одинИз(К2,Книги),not(К1=К2),
одинИз(К3,Книги),not(К1=К3),not(К2=К3),
одинИз(К4,Книги),not(К1=К4),not(К2=К4),not(К3=К4),
Пьеса = книга(_,пьеса), одинИз(Пьеса,Книги),
КнигаПоИстории = книга(_,история), одинИз(КнигаПоИстории,Книги),
ПроизведениеДмитриева = книга(дмитриев,_), одинИз(ПроизведениеДмитриева,Книги),
НаписалАлексеев = книга(алексеев,_), одинИз(НаписалАлексеев,Книги),
НаписалБорисов = книга(борисов,_), одинИз(НаписалБорисов,Книги),
НаписалКонстантинов = книга(константинов,_), одинИз(НаписалКонстантинов,Книги),
НаписалДмитриев = книга(дмитриев,_), одинИз(НаписалДмитриев,Книги),
% у пассажиров заполняется список книг, т.о. формируются все возможные комбинации решений.
% список пассажиров упорядоченный.
читал(Алексеев,К1),читал(Борисов,К2),читал(Константинов,К3),читал(Дмитриев,К4),
% ПРОВЕРКА ГИПОТЕЗЫ %
% Алексеев и Борисов, дочитав каждый свою книгу, условились на завтра обменяться ими.
Алексеев = книголюб(алексеев,_,[КнигаЧиталАлексеев,КнигаЧиталБорисов]),
Борисов = книголюб(борисов,_, [КнигаЧиталБорисов,КнигаЧиталАлексеев]),
% Поэт читал пьесу. (В смысле: поэт взял с собой пьесу
% т.е. это была его первая прочитанная книга и, возможно, единственная).
% поэт взял с собой пьесу
взялССобой(Поэт,Пьеса),
% Прозаик, очень молодой человек, выпустивший свою первую книгу, говорил, что он в жизни не читал и не читает ничего по истории.
not( читал( Прозаик, КнигаПоИстории)),
% Борисов купил произведение Дмитриева.
взялССобой(Борисов,ПроизведениеДмитриева),
% Дмитриев - не прозаик, т.к. прозаик выпустил всего одну книгу, а борисов купл одно из нескольких произведений Дмириева
одинИз(Дмитриев,Пассажиры),Дмитриев = книголюб(дмитриев,НеПрозаик,_),
not(НеПрозаик = "прозаик"),
% Никто из пассажиров не покупал и не читал книгу, написанную им самим.
not( читал( Алексеев, НаписалАлексеев)),
not( читал( Борисов, НаписалБорисов)),
not( читал( Константинов, НаписалКонстантинов)),
not( читал( Дмитриев, НаписалДмитриев)).
% процедура для фильтрации не уникальных решений
уникальные_решения([],Уникальные_Решения,Уникальные_Решения).
уникальные_решения([Решение|Хвост_Решений],Уникальные_Решения,Уникальные_Решения_Выход):-
not(одинИз(Решение,Уникальные_Решения)),
уникальные_решения(Хвост_Решений,[Решение|Уникальные_Решения],Уникальные_Решения_Выход).
уникальные_решения([Решение|Хвост_Решений],Уникальные_Решения,Уникальные_Решения_Выход):-
одинИз(Решение,Уникальные_Решения),
уникальные_решения(Хвост_Решений,Уникальные_Решения,Уникальные_Решения_Выход).
% формирует список уникальных решени
списокРешений(Список_Уникальных_Решений):-
findall(Пассажиры,ищемРешение(Пассажиры),Список_Всех_Решений),
уникальные_решения(Список_Всех_Решений,[],Список_Уникальных_Решений).
% процедура перебирает список решений и вызывает процедуру вывода каждого решения на экран в читабельном виде
выводРешений():-
списокРешений(Список_Уникальных_Решений),
выводРешений(Список_Уникальных_Решений).
выводРешений([]).
выводРешений([Решение|ОстальныеРешения]):-
nl,write("Вывод решения:"),nl,
write(tab,"Кто кем был?"),nl,
печатьРешенияКтоКемБыл(Решение),
write(tab,"Кто что читал?"),nl,
печатьРешенияКтоЧтоЧитал(Решение),
выводРешений(ОстальныеРешения).
% вывод каждого решения на экран в читабельном виде
% ответ на вопрос: "Кто кем был?"
печатьРешенияКтоКемБыл([]).
печатьРешенияКтоКемБыл(Пассажиры):-
Пассажиры = [Первый|Остальные],
Первый = книголюб(Фамилия,Жанр,_),
write(tab,tab,Фамилия, " был ", Жанр,"ом"),nl,
печатьРешенияКтоКемБыл(Остальные).
% ответ на вопрос: "Кто что читал?"
печатьРешенияКтоЧтоЧитал([]).
печатьРешенияКтоЧтоЧитал(Пассажиры):-
Пассажиры = [Первый|Остальные],
Первый = книголюб(Фамилия,_,СписокКниг),
write(tab,tab,Фамилия, " читал ", СписокКниг),nl,
печатьРешенияКтоЧтоЧитал(Остальные).
goal
% ОТВЕТЫ НА ВОПРОСЫ %
выводРешений().
Код Prolog:
DOMAINS s=string sl=s* sll=sl*
CONSTANTS
names=["Alekseev","Borisov","Konstantinov","Dmitriev"]
prof=["astronomiya","poeziya","proza","drama"]
PREDICATES
solve(sl,sl,sl,sll)
getProf(integer,s,sll,sl,sl,s)
nonC(sll)
member(sl,s,sl) member(sll,sl,sll)
CLAUSES
solve([M|Men],Nms1,Prfs2,[[M,Pr,Avt,PrA]|H]):- solve(Men,Nms0,Prfs0,H),
getProf(0,M,H,Prfs0,Prfs1,Pr), member(Nms0,Avt,Nms1),
Avt<>M, getProf(1,Avt,H,Prfs1,Prfs2,PrA), not(nonC([[M,Pr,Avt,PrA]|H])).
solve([],names,prof,[]).
/***************************************************/
getProf(0,M,H,X,X,Pr):- member(H,[_,_,M,Pr],_),!.
getProf(1,M,H,X,X,Pr):- member(H,[M,Pr|_],_),!.
getProf(_,_,_,X,Y,Pr):- member(X,Pr,Y).
/***************************************************/
nonC([["Alekseev","proza"|_],["Borisov",_,_,"astronomiya"]|_]).
nonC([["Alekseev",_,_,"astronomiya"],["Borisov","proza"|_]|_]).
nonC([["Alekseev",_,X,_]|_]):- X<>"Dmitriev".
nonC([["Borisov",_,X,_]|_]):-X<>"Konstantinov".
nonC([[_,"poeziya",_,X]|_]):- X<>"drama".
nonC([[_,"proza",_,"astronomiya"]|_]).
nonC([["Dmitriev","proza"|_]|_]).
/***************************************************/
member([X|Y],X,Y).
member([X|Y],Z,[X|H]):- member(Y,Z,H).
|