Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Funktsionalnoe_i_logicheskoe_programmirovanie.doc
Скачиваний:
17
Добавлен:
19.01.2023
Размер:
1.75 Mб
Скачать

Пример выполнения работы.

1. На донорском пункте работали Джеймс, Генри и Томас. Один был вампиром, другой - оборотнем, третий - лишь маньяком.

Сыщик из Скотланд-Ярда расследуя дело, опросил всех троих. Вот что он услышал:

ДЖЕЙМС: "Генри - вампир"

ГЕНРИ: "Либо Джеймс, либо Томас - оборотень"

ТОМАС: "На самом деле вампир - Джеймс!"

Солгал только оборотень, а остальные говорили правду. Но полицию интересовал только маньяк, которого и арестовали.

Кого же арестовала полиция?

Решение.

Будем искать решение с помощью предиката solution с тремя аргументами – первый соответствует виду Джеймса, второй Генри и третий – Томаса.

Сначала запишем в решение все возможные варианты с учетом того, что виды не совпадают:

solution(X,Y,Z):-kind(X),kind(Y),kind(Z),X<>Y,X<>Z,Y<>Z,

Теперь рассуждаем следующим образом – пусть Джеймс и Генри сказали правду, а соврал Томас, тогда добавим условия:

solution(X,Y,Z):-kind(X),kind(Y),kind(Z),X<>Y,X<>Z,Y<>Z,

Y="vampire", /*Джеймс сказал правду, что Генри вампир*/

X="werevolf", /*Генри сказал правду, что Джеймс оборотень…*/

X<>"vampire", /*Томас соврал, что Джеймс вампир*/

Z="werevolf"; /*совравший является оборотнем, значит Томас оборотень*/

kind(X),kind(Y),kind(Z),X<>Y,X<>Z,Y<>Z,

Y="vampire",

Z="werevolf", /*или Генри сказал правду, что Томас оборотень*/

X<>"vampire",

Z="werevolf".

Два варианта нам пришлось написать для реализации дизъюнкции в утверждении Генри.

Далее возможен второй вариант – врал Генри, соответствующие условия будут:

solution(X,Y,Z):-kind(X),kind(Y),kind(Z),X<>Y,X<>Z,Y<>Z,

Y="vampire",

X<>"werevolf",Z<>"werevolf",

X="vampire",

Y="werevolf".

Поскольку здесь отрицание дизъюнкции, правило получилось короче. И, наконец, последний вариант – врал Томас:

solution(X,Y,Z):-kind(X),kind(Y),kind(Z),X<>Y,X<>Z,Y<>Z,

Y<>"vampire",

X="werevolf",

X="vampire",

X="werevolf";

kind(X),kind(Y),kind(Z),X<>Y,X<>Z,Y<>Z,

Y<>"vampire",

Z="werevolf",

X="vampire",

X="werevolf".

Для ответа непосредственно на вопрос задачи, напишем последний предикат:

И получаем решение:

2. В семье пять человек: муж, жена, их сын, сестра мужа и отец жены. Их профессии - инженер, юрист, слесарь, учитель и экономист. Известно, что юрист и учитель - не кровные родственники. Слесарь младше экономиста, и оба играют в футбол за сборную своего завода. Инженер моложе учителя, но старше жены своего брата. Назовите профессии каждого.

Решение. Опишем предикаты для названий родственников и их профессий в виде фактов.

Далее, начинаем составлять соответствие, пусть переменные вида означают профессии, а - родственников. Одну из этих категорий можно задать в виде констант – присвоить им значения. Поскольку в задаче говорится об отношениях людей с определенными профессиями, то профессии и зададим как константы. На этом этапе можно убрать факты prof, они нам не понадобятся. Введены факты prof были для того, чтобы показать, с чего надо начинать решать подобные задачи. Впрочем, наличие этих фактов нам никак не помешает. Итак, начинаем писать основной предикат:

sootv(X1,Y1,X2,Y2,X3,Y3,X4,Y4,X5,Y5):-X1="engineer",X2="lawyer",X3="locksmith",X4="teacher",X5="economist",

Далее, другую категорию – родственников формируем с помощью фактов men, указывая, что у всех людей разная профессия:

sootv(X1,Y1,X2,Y2,X3,Y3,X4,Y4,X5,Y5):- X1="engineer",X2="lawyer",X3="locksmith",X4="teacher",X5="economist", men(Y1),men(Y2),men(Y3),men(Y4),men(Y5),Y1<>Y2,Y1<>Y3,Y1<>Y4, Y1<>Y5,Y2<>Y3,Y2<>Y4,Y2<>Y5,Y3<>Y4,

Y3<>Y5,Y4<>Y5,

Если запустить программу на этом этапе, у нас будет 120 вариантов решения, так как мы еще не указали дополнительных условий. Начинаем внимательно читать условия задачи: «Известно, что юрист и учитель - не кровные родственники». Добавим новый предикат для кровных родственников – relative. Очевидно, кровными родственниками будут являться пары муж-сын, жена-сын, муж-сестра и жена-отец.

Юрист у нас является родственником по имени Y2, а учитель – Y4. Добавляем в предикат sootv условия

not(relative(Y2,Y4)), not(relative(Y4,Y2)),

Заметьте, что добавить надо именно два условия, либо обойтись , например, одним первым условием, но тогда придется в предикате relative добавить строку вида

relative(X,Y):-relative(Y,X).

для учета всех пар кровных родственников.

Далее идет достаточно сложное условие «слесарь младше экономиста», сложность состоит в том, что мы не можем быть уверены насчет соотношения возрастов персонажей. Скажем, младше ли жена сестры, сын сестры, муж отца жены или наоборот? Тут лучше ввести новый предикат, означающий «старше» и задать в нем пары, относительно которых есть точная уверенность, а именно : муж и жена старше сына, отец жены старше сына – своего внука, отец старше жены.

Добавляем в sootv условие, что слесарь не старше экономиста

not(older(Y3,Y5))

Учесть, что слесарь и экономист играют в футбол, можно введя новый предикат male, скорее всего, имеется в виду, что в футбол играют только мужчины в этой семье.

Добавляем в sootv условия

male(Y3),male(Y5)

Аналогично, учтем, что инженер не старше учителя

not(older(Y4,Y1)) .

Далее сказано, что инженер старше жены своего брата ,но ведь только у одного персонажа в семье есть брат – у сестры мужа! Значит, можно смело написать

Y1="sister"

Осталось учесть последнее условие, что инженер старше жены – тут можно указать, что в этом случае жена не учитель (иначе инженер получится и младше учителя-жены и одновременно старше):

Y4<>"wife".

Окончательно, предикат sootv и цель будут выглядеть так:

После запуска получаем единственный ответ: