Скачиваний:
36
Добавлен:
01.05.2014
Размер:
549.89 Кб
Скачать

Часть III Современные методы программирования на Прологе

Выразительная мощность и высокий уровень логического программирования позволяют писать программы, которые трудно разрабатывать с помощью обычных языков программирования. Средства логического программирования поддержи­вают парадигмы, пригодные для решения различных задач, используют альтерна­тивные структуры данных и механизмы доступа к ним.

Рассмотренные в предыдущей части простые программы на Прологе являются примерами использования основных методов программирования, реализуемых в контексте логического программирования. В этой части книги собраны более совершенные методы, развитые в рамках логического программирования и использующие специальные свойства логических программ. Будет показано, к каким преимуществам приводит их применение.

Глава 14 Недетерминированное программирование

Одним из отличий вычислительной модели логического программирования от моделей обычного программирования является недетерминизм. Недетерминизм это техническое понятие, используемое для сжатого определения абстрактных моделей вычислений. Однако недетерминизм не только мощная теоретическая идея. но и полезное средство описания и реализации алгоритмов, В данной главе будет показано, как при недетерминированном подходе можно конструировать компактные и эффективные программы.

Интуитивно ясно, что недетерминированная машина, перед которой возникло несколько альтернативных путей решения, осуществляет корректный выбор очередного действия. Подлинно недетерминированную машину реализовать нельзя, однако ее можно моделировать или аппроксимировать. В частности. Пролог-интерпретатор, как описано в гл. 6, аппроксимирует недетерминированное поведение интерпретатора абстрактных логических программ с применением механизма последовательного поиска и возвратов. Однако тот факт , что недетерминизм только «моделируется», но «реально не присутствует», для недетерминированного мышления во многих случаях несуществен, точно гак же как несущественны для символьного мышления детали обработки указателей и процессе унификации.

14.1. Метод «образовать и проверить»

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

Обычно программы, реализующие метод «образовать и проверить», конструи­ровать проще, чем программы, в которых решение находится непосредственно, однако они менее эффективны. Стандартный прием оптимизации программ типа «образовать и проверить» заключается в стремлении погрузить программу проверки в программу генерации предполагаемых решений настолько «глубоко», насколько это возможно. В пределе программа проверки полностью переплетается с программой генерации предполагаемых решений, которая начинает порождать

только корректные решения.

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

find(X)generate(X), test(X).

Эта Пролог-программа действует подобно обычной процедурной программе, выполняющей генерацию вариантов и их проверку. Если при решении вопроса find(X)?. успешно выполняется цель generate(X) с выдачей некоторого X, то затем выполняется проверка test(X). Если проверка завершается отказом, то произво­дится возвращение к цели generate, с помощью которой генерируется следующий элемент. Процесс продолжается итерационно до тех пор, пока при успешной проверке не будет найдено решение с характерными свойствами или генератор не исчерпает все альтернативные решения.

Однако программисту нет необходимости интересоваться циклом «образовать и проверить». Он может рассматривать этот метод более абстрактно, как пример недетерминированного программирования. В этой недетерминированной програм­ме генератор вносит предположение о некотором элементе из области возможных ре­шений, а затем просто проверяется, корректно ли данное предположение генератора.

В качестве генератора обычно используется программа для предиката member (программа 3.12), порождающая множество решений. На вопрос member(X[a,b,c])? будут даны в требуемой последовательности решения Х = а, Х = b и Х = с. Таким образом, предикат member можно использовать в программах, реализующих метод «образовать и проверить» для недетерминированного выбора корректного элемента из некоторого списка.

Программа 14.1 представляет собой простой пример реализации метода «образовать и проверить» с использованием в качестве генератора предиката member. Эта программа предназначена для идентификации частей речи предложе­ния. Предполагается, что предложение представлено списком слов и существует база данных фактов, задающих части речи для определенных слов. Для задания частей речи используются унарные предикаты, аргументами которых являются слова, например, предикат существительное (man) указывает, что man - существительное, Отношение глагол(Предложение, Слово) истинно, если Слово в предложений Предложение является глаголом. Аналогичный смысл имеют предикаты существительное/2 и артикль/2. На вопрос глагол([а,man,loves,a,woman),V)? методом «образовать и проверить» будет дан ответ V= loves. Слова предложения генерируются

глагол (Предложение, Глагол)

Глагол - глагол в списке слов Предложение.

глагол (Предложение, Слово) 

member (Слово, Предложение), глагол (Слово).

существительное (Предложение, Слово)

member (Слово, Предложение), существительное(Слово).

артикль (Предложение, Слово)

member (Слово, Предложение), артикль (Слово).

Словарь

существительное (man). существительное(woman).

артикль(а). глагол (loves).

Программа 14.1. Отыскание частей речи в предложении.

с помощью предиката member и затем проверяется, являются ли они глаголами.

Другой простой пример-проверка существования в двух списках общего элемента. Рассмотрим предикат intersect (Xs,Ys), который истинен, если списки Xs и Ys имеют общий элемент. Определим его предложением

intersect(Xs.Ys)  member(X,Xs), member(X,Ys).

Первая цель member в теле этого предложения генерирует элементы из первого списка, а с помощью второй цели member проверяется, входят ли эти элементы во второй список. Описывая эту программу как недетерминированную, можно говорить, что первая цель делает предположение о том, что Х содержится в списке Хs, а вторая цель проверяет, является ли Х элементом списка Ys.

Отметим, что рассматриваемое предложение в виде Пролог-программы эффективно реализуется двумя вложенными циклами. Внешний цикл обеспечивает перебор элементов первого списка, а во внутреннем цикле проверяется, является ли выбранный из первого списка элемент элементом второго списка. Следовательно, поведение этой недетерминированной логической программы в принятой модели исполнения Пролог-программ напоминает поведение аналогичных программ, разработанных средствами Фортрана, Паскаля или Лиспа.

Следующее определение предиката member с использованием предиката append

member(X,Xs) append(As,[X | Bs],Xs)

само по существу является программой, в которой реализуется принцип «образовать и проверить». Однако в этой программе два шага метода сливаются в процессе унификации. С помощью цели append производится расщепление списка и тут же выполняется проверка, является ли Х первым элементом второго списка.

Остановимся на вопросе оптимизации программ, реализующих принцип «образовать и проверить» посредством внедрения шага проверки в генератор предполагаемых решений. Рассмотрим еще один пример применения обсуждаемого прин­ципа программу 3.20 для сортировки перестановками. Предложение верхнего уровня программы имеет вид

sort(Xs,Ys) permutation(Xs,Ys), ordered(Ys).

Абстрактно эта программа, действуя недетерминированно, генерирует с помощью цели permutation(Xs.Ys) предположительно корректную перестановку, а с помощью цели ordered проверяет, действительно ли эта перестановка упорядочена должным образом.

В операционной интерпретации данная программа выглядит следующим образом. Вопрос, включающий отношение sort, сводится к вопросу с отношениями permutation и ordered. В результате возникает цикл, управляемый отказами. Некоторая перестановка элементов списка генерируется посредством отношения permutation и проверяется с помощью отношения ordered. Если перестановка оказывается неупорядоченной, то происходит возврат к цели permutation, которая обеспечивает генерацию новой перестановки, подлежащей проверке на упорядоченность, В конце концов будет сгенерирована упорядоченная перестановка и процесс вычислений прекратится,

Сортировка перестановками - крайне неэффективный алгоритм сортировки. имеющий экспоненциальную по размеру сортируемого списка сложность. Более приемлемый алгоритм получается, если внедрить проверку в часть алгоритма. ответственную за генерацию. Тогда генератор permutation выбирает из списка произвольный элемент и рекурсивно выполняет перестановку остальных элементов списка. Предикат ordered проверяет упорядоченность первых двух элементов этой перестановки, затем рекурсивно проверяет остальные элементы списка. Если рассматривать объединение рекурсивных целей permutation и ordered как рекурсивный процесс сортировки, то последний составляет основу алгоритма сортировки вставками (см. программу 3.21). Для сортировки списка сортируется его хвост, а головка списка вставляется на место, сохраняющее порядок расположения элементов. Выбор произвольного элемента должен быть заменен выбором первого элемента.

Еще один пример преимущества «сплетения» процессов генерации и проверки дает программа для решения задачи об N ферзях.

Требуется разместить N ферзей на квадратной доске размера N*N так, чтобы на каждой горизонтальной, вертикальной или диагональной линии было не больше одной фигуры. В первоначальной формулировке этой задачи шла речь о размещении 8 ферзей на шахматной доске таким образом, чтобы они, согласно правилам игры в шахматы, не угрожали друг другу. Отсюда пошло название задачи о ферзях.

Эта задача была хорошо изучена в литературе по занимательной математике. Для N = 2 и N = 3 решения не существует; единственное, без учета симметричного, решение при N=4 показано на рис. 14.1. Для N=8 существует 88 (а с учетом симметричных - 92) решений этой задачи.

Программа 14.2-упрощенная программа для решения задачи об N ферзях. Отношение queen(N, Qs) истинно, если Qs- решение задачи об N ферзях. Решение представляется некоторой перестановкой списка от 7 до N. Порядковый номер элемента этого списка определяет номер вертикали, а сам элемент-номер горизонтали, на пересечении которых стоит ферзь. Так, решение [2,4,1,3] задачи о четырех ферзях соответствует решению, изображенному на рис. 14.1. Подобное описание решений и программа их генерации неявно предполагают, что в любом решении задачи о N ферзях на каждой горизонтали и на каждой вертикали будет находиться по одному ферзю.

Q

Q

Q

Q

Рис. 14.1. Решение задачи о четырех ферзях.

queens(N, Queens)

Queens размещение ферзей, которое является решением задачи о N ферзях, представляемое перестановкой списка чисел [1,2,..,N].

queens(N,Qs) 

range(1,N,Ns), pemiutation(Ns,Qs), safe(Qs)

safe(Qs)

Qs - безопасное размещение ферзей.

safe([Q | Qs]) safe(Qs), not attack (Q,Qs). safe([ ]).

attack(X,Xs)  attack (X, 1, Xs).

attack (X,N,[Y | Ys]) X:-Y+N;X:= Y-N.

attack(X,N,[Y | Ys]) N1 := N+1; attack (X,N1, Ys).

permutation(Xs,Ys)См. программу 3.20. range(l,N,Ns)См. программу 8.12.

Программа 14.2. Простая программа для решения задачи о N ферзях с использованием метода «образовать и проверить».

Программа 14.2 выполняется следующим образом. Сначала с помощью предиката range образуется список Ns, содержащий числа от 1 до N. Затем начинается выполнение цикла «образовать и проверить». Посредством предиката permutation генерируется перестановка Qs элементов списка Ns, которая затем проверяется предикатом safe(Qs), принимающим значение «истинно», если перестановка Qs является решением задачи. Поскольку на одной и той же вертикали или горизонтали одновременно не могут размещаться два ферзя, этот предикат должен обеспечить лишь проверку того, не угрожают ли друг другу два ферзя по какой-нибудь диагонали. Предикат safe имеет рекурсивное определение. Размещение ферзей безопасно, если ферзи, представляемые хвостом этого списка, не атакуют друг друга, а ферзь, представляемый головой этого списка, не атакует никакого другого ферзя. В определении предиката attack (Q,Qs) использована изящная инкапсуляция взаимосвязи диагоналей. Два ферзя находятся на одной и той же диагонали на расстоянии М вертикалей друг от друга, если номер горизонтали одного ферзя на М больше или на М меньше, чем номер горизонтали другого ферзя. В программе 14.2 это выражается первым предложением attack/3. Смысл предиката attack (Q,Qs) можно выразить словами: «Ферзь Q атакует некоторого ферзя из списка Qs». Диагонали проверяются итерационно до тех пор, пока не будет достигнут конец доски,

Программа 14.2 не способна распознавать симметричные решения. Например, на вопрос queens (4, Qs)? она дает два ответа, а именно решения: Qs =[2,4.1,3] и [3,1,4,2].

Хотя логическая программа 14.2 написана грамотно, она весьма неэффективна. В ней генерируется много перестановок, которые заведомо не могут быть решениями. Как и в случае с программой сортировки перестановками, рассматриваемая про­грамма может быть улучшена внедрением проверки, в данном случае предиката safe, в генератор перестановок.

Вместо генерации полной перестановки, т.е. размещения всех ферзей и после­дующей проверки размещения, можно выполнять проверку корректности размеще­ния каждого ферзя непосредственно после его размещения. Программа 14.3 пред­назначена для решения задачи об N ферзях при последовательном размещении ферзей. В этой программе сохраняется реализация принципа «образовать и прове-

queens(N .Queens)

Queens -размещение ферзей, которое является решением -задачи о N ферзях, представляемое перестановкой списка чисел [1,2,..,N].

queens(N,Qs) range(1,N,Ns), queens(Ns,[ ],Qs).

queens(UnplacedQs,SafeQs,Qs) 

select (Q, Unplaced Qs, Unplaced Qs1),

not attack (Q, Safe Qs),

queens(UnplacedQs1,[Q | SafeQs],Qs).

queens([ ],Qs,Qs).

select (X l Xs,Ys)См. программу 3.19.

attack(A, Xs)Cм. программу 14.2.

Программа 14.3. Программа для решения задачи о N ферзях посредством последовательного размещения ферзей.

рить», что отличает ее от программы сортировки вставками, которая после преобразования стала детерминированной. Генератором в рассматриваемой программе является предикат select, проверка реализуется предикатом attack, или, более точно, его отрицанием.

Чтобы проверить, в безопасном ли положении находится новый ферзь, необходимо знать позиции ранее размещенных ферзей. Следовательно, искомое решение строится по принципу снизу вверх с применением накопителя. Здесь используется базовый метод, описанный в разд. 7.5. Использование накопителя приводит к размещению ферзей, начиная с правой границы доски. Программа 14.3 на вопрос queens (4,Qs) дает два решения в порядке, обратном порядку решений по программе 14.2.

Следующая задача состоит в раскрашивании плоской карты так, чтобы никакие две смежные области на ней не были окрашены в одинаковый цвет. Эта знаменитая задача, известная уже сотни лет, была решена в 1976 г., когда было доказано, что для раскрашивания любой плоской карты достаточно использовать четыре краски. На рис. 14.2 показана простая карта, для корректного раскрашивания которой требуется четыре цвета. Это можно доказать путем перечисления всех возможных вариантов раскраски. Следовательно, для решения задачи использование четырех красок является необходимым и достаточным.

В программе 14.4, предназначенной для решения задачи о раскрашивании карты, также использован принцип «образовать и проверить». Программа реализует следующий недетерминированный алгоритм:

для каждой области карты

- выбрать цвет,

- выбрать из оставшихся цветов (или проверить) цвета соседних областей

Для реализации алгоритма необходимо выбрать подходящие структуры данных. Карта представляется списком областей, каждая из которых имеет имя, цвет и

a

b

c

d

e

f

Рис. 14.2. Paскрашивание карты четырьмя цветами.

color _map( Map,Colors)

Плоская карта Map раскрашивается красками Colors так, чтобы никакие две соседние области не были окрашены в одинаковый цвет. Карта представляется списком смежных областей region (Name,Color,Neighbors), где Name имя области. Color -ее цвет. Neighbors- цвета раскраски соседних областей. Программа может быть использована без начальной конкретизации всех цветов.

color_map([Region | Regions], Colors) 

color_region (Region, Colors),

coIor_map(Regions,Colors). color_map([ ], Сolors).

color_region (Region. Colors)

Область Region и смежные с ней области окрашиваются в цвета Colors так, чтобы цвет этой области отличался от цвета, в который окрашены соседние области.

color_region(region(Name, Col or, Neighbors), Colors)

select(Color, Colors, Colors 1),

members (Neighbors, Colors 1).

select(X,Xs,Ys)Cм. программу 3.19. rnembers(Xs,Ys)См. программу 7.6.

Программа 14.4. Раскрашивание карты.

список цветов, в которые окрашены смежные области. Например, карта, изображен­ная на рис. 14.2, представляется списком

region (а. А, [В, С, D]). region(b,B,[A,C,E]),

region (с. С, [А, В, D, Е, F]), region (d, D, [А, С, F]), region(e,E,[B,C,F]), region(f,F[C,D,E])].

Для того чтобы избежать раскраски одной и той же области в разные цвета на разных итерациях алгоритма, используются общие переменные.

Отношением верхнего уровня рассматриваемой программы является со1оr_ тар (Map,Colors), где Map - карта, представляемая описанным выше способом, Colors- список цветов, используемых для раскрашивания карты. Выберем цвета: красный, желтый, голубой и белый. Ядро алгоритма - определение отношения color_ region (Region, Colors):

color__region (region (Name, Color, Neighbors), Colors)

select (Color, Colors, Colors 1),

member (Neighbors, Colors I).

Цели select и members в зависимости от того, конкретизированы или нет их аргументы, могут либо производить генерацию вариантов, либо выполнять проверку.

Итогом выполнения программы о раскрашивании карты является конкретизация структуры данных-карты. Вызовы предикатов select и members могут рассматриваться как описания локальных ограничений. Предикаты либо генерируют предполагаемое решение посредством конкретизации элементов структуры, либо проверяют, удовлетворяют ли конкретизированные значения локальным ограничениям.

В качестве последнего примера рассмотрим решение логической головоломки. Поведение этой программы будет подобно поведению программы для решения задачи о раскрашивании карты. Логическая головоломка состоит из нескольких фактов относительно небольшого числа объектов, которые имеют различные атрибуты. Минимальное число фактов относительно объектов и атрибутов связано с желанием выдать единственный вариант назначения атрибутов объектам.

Тестовые данные

test_color(Name,Map) 

map (Name, Map),

colors(Name, Colors),

color_map(Map, Colors).

map(test, [region(a, A, [B, C, D]),

region (b,B, [A, C,E]), region (c,C, [A, B,D,E,F]),

region (d, D, [A,C, F]), region (e, E, [B, C, F]),

region(f,F,[C,D,E])]).

map(west_europe, [region (portugal, P, [E]), region(spain, E, [F, P]),

region(france,F, [E,1,S,B,WG,L]), region(belgium,B,[F,H,L,WG]),

region (holland, H, [B, WG]), region(west_germany, WG, [F, A, S, H. B, L]),

region (luxembourg, L, [F, B, WG]), region (italy, I, [F, A, S]),

region (Switzerland, S, [F, I, A, WG]), region (austria, A, [I, S, WG])]).

colors(X,[red,yellow, blue, white]).

Программа 14.5. Тестовые данные для задачи о раскрашивании карты.

Метод решения логических головоломок опишем на следующем примере.

Три друга заняли первое, второе и третье места в соревнованиях универсиады. Друзья-разной национальности, зовут их по-разному, и любят они разные виды спорта.

Майкл предпочитает баскетбол и играет лучше чем американец. Израильтянин Саймон играет лучше теннисиста. Игрок в крикет занял первое место.

Кто является австралийцем? Каким спортом занимается Ричард?

Подобные логические головоломки изящно решаются посредством конкретизации значений подходящей структуры данных и выделения значения, приводящего к решению. Каждый ключ к разгадке преобразуется в факт относительно структуры данных. Это может быть сделано с использованием абстракции данных до определения точной формы структуры данных. Проанализируем первый ключ к разгадке: «Майкл предпочитает баскетбол и играет лучше чем американец». Очевидно, речь идет о двух разных людях. Одного зовут Майклом и он занимается баскетболом, в то время как второй - американец. Кроме того, Майкл лучше играет в баскетбол, чем американец. Предположим, что Друзья структура данных, подлежащая конкретизации, тогда наш ключ может быть выражен следующей конъюнкцией целей:

играет __лучше(мужчина 1 ,Мужчина2,Друзья),

имя(Мужчина 1 ,Майкл),спорт(Мужчина 1 .баскетбол),

национальность(Мужчина2,американец).

Аналогично второй ключ можно представить конъюнкцией целей:

играет _лучше(мужчина1,Мужчина2,Друзья),

имя(Мужчина1 ,Саймон),национальность(Мужчина1,израильтянин),

спорт(Мужчина2,тенннс).

Наконец, третий ключ к разгадке выразится следующим образом:

первый(Друзья.Мужчина),спорт(Мужчина,крикет).

Базовая программа для решения головоломок представлена программой 14.6. Вычислению подлежит отношение решить _головоломку(Головоломка, Решение), где Решение является решением головоломки Головоломка, Головоломка представля-

решить головоломку (Головоломки, Решение)

Решение - решение головоломки Головоломки, которая представляется структурой головоломка (Ключи, Вопросы, Решении).

решить_головоломку (головоломка (Ключи, Вопросы, Решение), Решение) решить(Ключи),

решить (Вопросы).

решить ([Ключ [Ключи])

Ключ, решить (Ключи). решить([ ]).

Программа 14.6. Решатель головоломок.

ется структурой головоломка(Ключи, Вопросы, Решение), где структура данных, подлежащая конкретизации, представляется ключами и вопросами, а получаемые значения определяются аргументом Решение.

Программа решитьоловоломку тривиальна. Все, что она делает, состоит в последовательном решении каждого ключа и вопроса, которые представляются как цели Пролога и выполняются с использованием метапеременных.

Ключи и вопросы для нашего примера даны в программе 14.7. Рассмотрим структуру, представляемую ключами, для решения этой головоломки. Каждый человек имеет три атрибута и может быть представлен структурой друг{Имя,Страна,Спорт). Есть три друга, распределение мест которых в итоге соревнований имеет существенное значение. Это наводит на мысль выбрать в качестве структуры данных для решения задачи упорядоченную последовательность из трех элементов, т. е. список:

[Друг(N1,C1,S1), друг(N2.C2,S2), друг (N3,C3,S3)]. Тестовые данные

тест для головоломки (Имя, головоломка (Ключи, Вопросы, Решение))

структура (Имя, Структура),

ключи(Имя, Структура, Ключи),

вопросы (Имя, Структура, Вопросы, Решение).

структуpa(Tecт,[Дpyr(N1,C1,S1),дpyr(N2,C2,S2),дpyr(N3,C3,S3)]).

ключи (тест, Друзья,

[(играет_лучше (Мужчина1 Ключ1,Мужчина2 Ключ1, Друзья), % Ключ 1

имя(Мужчина1 Ключ1,майкл),спорт (Мужчина1 Ключ1, баскетбол),

национальность(Мужчина2Ключ1,американец)),

(играет_лучше(Мужчина1Ключ2,Мужчина2Ключ2, Друзья), % Ключ 2

имя(Мужчина1 Ключ2,саймон), национальность (Мужчина 1 Ключ2,

израильтянин),

спорт(Мужчина2Ключ2,теннис)),

первый (Друзья. МужчинаКлюч3),

спорт(МужчинаКлюч3, крикет)) % Ключ 3

]).

вопросы (тест. Друзья,

[принадлежит (Q1, Друзья),

имя(Q1,Имя),

национальность (Q1, австралиец), % Вопрос 1

принадлежит (Q2,Дручья),

имя(Q2,ричард),

спорт (Q2,Спорт) % Вопрос 2

],

[[‘Имя австралийца -',Имя], [‘Ричард играет в ' ,Спорт]]

).

играет_лучше(А, В, [А, В, С]).

играет_лучше(А, С, [А, В, С]).

играет..лучше (В, С, [А, В, С]).

имя(друг(А,В,С).А).

национальность (друг(А. В, С), В).

спорт (друг (А, В, С), С).

первый ([X | Xs], X).

Программа 14.7. Описание головоломки.

В программе 14.7 даны определения условий играет_лучше, имя, национальность, спорт и первый, которые, очевидно, легко программируются.

Объединение программ 14.6 и 14.7 дает нечто гигантское на тему «образовать и проверить». Каждая из целей играет_лучше и принадлежит (member) имеет дело с людьми, а остальные цели обращаются к атрибутам людей. Какие функции они выполняют генерацию или проверку, зависит от того, конкретизированы их аргументы или нет. Для любопытных сообщаем ответ нашей головоломки: Майкл-австралиец, а Ричард играет в теннис.

Упражнения к разд. 14.1

1. Напишите программу вычисления целочисленного квадратного корня из натурального числа N, определяемого как число I, такое, что I2  N, но (I + 1)2 > N. Используйте определение предиката between/3 (см. программу 8.5) для генерирования последовательности натуральных чисел с помощью механизма возвратов.

2. Напишите программу для решения задачи об устойчивых браках (Sedgewick, 1983), формулируемую следующим образом.

Предположим, что N мужчин и N женщин желают вступить в брак. Каждый мужчина имеет список всех женщин, упорядоченных по его вкусу. Подобный список, но, конечно, мужчин, есть и у каждой женщины. Задача состоит в нахождении устойчивого множества

браков.

Множество браков неустойчиво, если два человека, не состоящие друг с другом в браке, хотят образовать такой союз. Предположим, например, что существуют двое мужчин и В) и две женщины (X и Y), такие, что А предпочитает X, В предпочитает Y, Х предпочитает A и Y предпочитает В. Пара браков A - Y и В - Х неустойчива, так как А предпочитает X, а не Y, в то время как Х отдает предпочтение А, а не В.

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

авраам: хана тамар звия руфь сара

беньямин: звия хана руфь сара тамар

хайм: хана руфь тамар сара звия

давид: звия руфь хана сара тамар

елеазар: тамар руфь хана звия сара

звия: елеазар авраам давид беньямин хайм

хана: давид елеазар бенъямин авраам хайм

руфь: авраам давид беньямин хайм елеазар

сара: хайм беньямин давид авраам елеазар

тамар: давид беньямин хайм елеазар авраам

3. Используйте программу 14.4 для раскраски карты Западной Европы. Названия государств даны в программе 14.5.

4. Напишите программу для решения следующей логической головоломки. В пяти домах окрашенных в разные цвета, обитают мужчины разных национальностей. Они держат разных животных, предпочитают разные напитки и курят сигареты разных марок. Известно, что:

1. Англичанин живет в красном доме.

2. У испанца есть собака.

3. Кофе пьют в зеленом доме.

4. Украинец пьет чай.

5. Зеленый дом-первый по правую руку от дома цвета слоновой кости.

6. Курильщик «Уинстона» держит улиток.

7. Сигареты «Кул» курят в желтом доме.

8. Молоко пьют в среднем доме.

9. Норвежец живет в крайнем слева доме.

10. Мужчина, курящий «Честерфилд», живет в доме, соседнем с домом мужчины, у которого есть лиса.

11. Сигареты «Кул» курят в доме, соседнем с домом, где имеется лошадь.

12. Мужчина, предпочитающий «Лаки страйк», пьет апельсиновый сок.

13. Японец курит сигареты «Парламент».

14. Норвежец живет в доме рядом с голубым домом. Вопросы: «У кого есть зебра?», «Кто пьет воду?».

5. Используя алгоритм Хопкрофта и Тарьяна (Dec, 1974; Even, 1979), напишите программу проверки планарности графа.

Соседние файлы в папке prolog14_end