11.2. Стратегия поиска в глубину
11.2. Стратегия поиска в глубину
Существует много различных подходов к проблеме поиска решающего пути для задач, сформулированных в терминах пространства состояний. Основные две стратегии поиска — это поиск в глубину и поиск в ширину. В настоящем разделе мы реализуем первую из них.
Мы начнем разработку алгоритма и его вариантов со следующей простой идеи:
Для того, чтобы найти решающий путь Реш из заданной вершины В в некоторую целевую вершину, необходимо:
• если В — это целевая вершина, то положить Реш = [В], или
• если для исходной вершины В существует вершина-преемник В1, такая, что можно провести путь Реш1 из В1 в целевую вершину, то положить Реш = [В | Peш1].
Рис. 11.4. Пример простого пространства состояний: а — стартовая вершина, f и j — целевые вершины. Порядок, в которой происходит проход по вершинам пространства состояний при поиске в глубину: а, b, d, h, e, i, j. Найдено решение [a, b, e, j]. После возврата обнаружено другое решение: [а, с, f].
На Пролог это правило транслируется так:
решить( В, [В] ) :-
цель( В).
решить( В, [В | Реш1] ) :-
после( В, В1 ),
решить( В1, Реш1).
Эта программа и есть реализация поиска в глубину. Мы говорим "в глубину", имея в виду тот порядок, в котором рассматриваются альтернативы в пространстве состояний. Всегда, когда алгоритму поиска в глубину надлежит выбрать из нескольких вершин ту, в которую следует перейти для продолжения поиска, он предпочитает самую "глубокую" из них. Самая глубокая вершина — это вершина, расположенная дальше других от стартовой вершины. На рис. 11.4 мы видим на примере, в каком порядке алгоритм проходит по вершинам. Этот порядок в точности соответствует результату трассировки процесса вычислений в пролог-системе при ответе на вопрос
?- решить( а, Реш).
Поиск в глубину наиболее адекватен рекурсивному стилю программирования, принятому в Прологе. Причина этого состоит в том, что, обрабатывая цели, пролог-система сама просматривает альтернативы именно в глубину.
Поиск в глубину прост, его легко программировать и он в некоторых случаях хорошо работает. Программа для решения задачи о восьми ферзях (см. гл. 4) фактически была примером поиска в глубину. Для того, чтобы можно было применить к этой задаче описанную выше процедуру решить, необходимо сформулировать задачу в терминах пространства состояний. Это можно сделать так:
• вершины пространства состояний — позиции, в которых поставлено 0 или более ферзей на нескольких последовательно расположенных горизонтальных линиях доски;
• вершина-преемник данной вершины может быть получена из нее после того, как в соответствующей позиции на следующую горизонтальную линию доски будет поставлен еще один ферзь, причем таким образом, чтобы ни один из уже поставленных ферзей не оказался под боем;
• стартовая вершина — пустая доска (представляется пустым списком);
• целевая вершина — любая позиция с восемью ферзями (правило получения вершины-преемника гарантирует, что ферзи не бьют друг друга).
Позицию на доске будем представлять как список Y-координат поставленных ферзей. Получаем программу:
после( Ферзи, [Ферзь | Ферзи] ) :-
принадлежит( Ферзь, [1, 2, 3, 4, 5, 6, 7, 8] ),
% Поместить ферзя на любую вертикальную линию
небьет( Ферзь, Ферзи).
цель( [ _, _, _, _, _, _, _, _ ] )
% Позиция с восемью ферзями
Отношение небьет означает, что Ферзь не может поразить ни одного ферзя из списка Ферзи. Эту процедуру можно легко запрограммировать так же, как это сделано в гл. 4. Ответ на вопрос
?- решить( [], Решение)
будет выглядеть как список позиций с постепенно увеличивающимся количеством поставленных ферзей. Список завершается "безопасной" конфигурацией из восьми ферзей. Механизм возвратов позволит получить и другие решения задачи.
Поиск в глубину часто работает хорошо, как в рассмотренном примере, однако наша простая процедура решить может попасть в затруднительное положение, причем многими способами. Случится ли это или нет — зависит от структуры пространства состояний. Для того, чтобы затруднить работу процедуры решить в примере рис. 11.4, достаточно внести в задачу совсем небольшое изменение: добавить дугу, ведущую из h в d, чтобы получился цикл (рис. 11.5). В этом случае поиск будет выглядеть так: начиная с вершины а, спускаемся вплоть до h, придерживаясь самой левой ветви графа. На этот раз, в отличие от рис. 11.4, у вершины h будет преемник d. Поэтому произойдет не возврат из h, а переход к d. Затем мы найдем преемника вершины d, т.е. вершину h, и т.д., в результате программа зациклится между h и d.
Рис. 11.5. Начинаясь в а, поиск в глубину заканчивается бесконечным циклом между d и h: a, b, d, h, d, h, d ….
Очевидное усовершенствование нашей программы поиска в глубину — добавление к ней механизма обнаружения циклов. Ни одну из вершин, уже содержащихся в пути, построенном из стартовой вершины в текущую вершину, не следует вторично рассматривать в качестве возможной альтернативы продолжения поиска. Это правило можно сформулировать в виде отношения
вглубину( Путь, Верш, Решение)
Как видно из рис. 11.6, Верш — это состояние, из которого необходимо найти путь до цели; Путь — путь (список вершин) между стартовой вершиной и Верш; Решение — Путь, продолженный до целевой вершины.
Рис. 11.6. Отношение вглубину( Путь, В, Решение).
Для облегчения программирования вершины в списках, представляющих пути, будут расставляться в обратном порядке. Аргумент Путь нужен для того,
(1) чтобы не рассматривать тех преемников вершины Верш, которые уже встречались раньше (обнаружение циклов);
(2) чтобы облегчить построение решающего пути Решение. Соответствующая программа поиска в глубину показана на рис. 11.7.
решить( Верш, Решение) :-
вглубину( [], Верш, Решение).
вглубину( Путь, Верш, [Верш | Путь] ) :-
цель( Верш).
вглубину( Путь, Верш, Реш) :-
после( Верш, Верш1),
not принадлежит( Верш1, Путь), % Цикл?
вглубину( [Верш | Путь], Верш1, Реш).
Рис. 11.7. Программа поиска в глубину без зацикливания.
Теперь наметим один вариант этой программы. Аргументы Путь и Верш процедуры вглубину можно объединить в один список [Верш | Путь]. Тогда, вместо вершины-кандидата Верш, претендующей на то, что она находится на пути, ведущем к цели, мы будем иметь путь-кандидат П = [Верш | Путь], который претендует на то, что его можно продолжить вплоть до целевой вершины. Программирование соответствующего предиката
вглубину( П, Решение)
оставим читателю в качестве упражнения.
Наша процедура поиска в глубину, снабженная механизмом обнаружения циклов, будет успешно находить решающие пути в пространствах состояний, подобных показанному на рис. 11.5. Существуют, однако, такие пространства состоянии, в которых наша процедура не дойдет до цели. Дело в том, что многие пространства состояний бесконечны. В таком пространстве алгоритм поиска в глубину может "потерять" цель, двигаясь вдоль бесконечной ветви графа. Программа будет бесконечно долго обследовать эту бесконечную область пространства, так и не приблизившись к цели. Пространство состояний задачи о восьми ферзях, определенное так, как это сделано в настоящем разделе, на первый взгляд содержит ловушку именно такого рода. Но оказывается, что оно все-таки конечно, поскольку Y-координаты выбираются из ограниченного множества, и поэтому на доску можно поставить "безопасным образом" не более восьми ферзей.
вглубину2( Верш, [Верш], _ ) :-
цель( Верш).
вглубину2( Верш, [Верш | Реш], МаксГлуб) :-
МаксГлуб > 0,
после( Верш, Верш1),
Maкс1 is МаксГлуб - 1,
вглубину2( Верш1, Реш, Maкс1).
Рис. 11.8. Программа поиска в глубину с ограничением по глубине.
Для того, чтобы предотвратить бесцельное блуждание по бесконечным ветвям, мы можем добавить в базовую процедуру поиска в глубину еще одно усовершенствование, а именно, ввести ограничение на глубину поиска. Процедура поиска в глубину будет тогда иметь следующие аргументы:
вглубину2( Верш, Решение, МаксГлуб)
Не разрешается вести поиск на глубине большей, чем МаксГлуб. Программная реализация этого ограничения сводится к уменьшению на единицу величины предела глубины при каждом рекурсивном обращений к вглубину2 и к проверке, что этот предел не стал отрицательным. В результате получаем программу, показанную на рис. 11.8.
Упражнения
11.1. Напишите процедуру поиска в глубину (с обнаружением циклов)
вглубину1( ПутьКандидат, Решение)
отыскивающую решающий путь Решение как продолжение пути ПутьКандидат. Оба пути представляйте списками вершин, расположенных в обратном порядке так, что целевая вершина окажется в голове списка Решение.
11.2. Напишите процедуру поиска в глубину, сочетающую в себе обнаружение циклов с ограничением глубины, используя рис. 11.7 и 11.8.
11.3. Проведите эксперимент по применению программы поиска в глубину к задаче планирования в "мире кубиков" (рис. 11.1).
11.4. Напишите процедуру
отобр( Ситуация)
для отображения состояния задачи "перестановки кубиков". Пусть Ситуация — это список столбиков, а столбик, в свою очередь, — список кубиков. Цель
отобр( [ [a], [e, d], [с, b] ] )
должна отпечатать соответствующую ситуацию, например так:
e с
a d b
==============
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Стратегия планирования
Стратегия планирования Стратегия (policy) планирования— это характеристики поведения планировщика, которые определяют, что и когда должно выполняться. Стратегия планирования определяет глобальный характер поведения системы и отвечает за оптимальное использование
Стратегия продвижения
Стратегия продвижения План выведения интернет-магазина в топ включает в себя перечисленные ниже пункты:• подбор запросов, составление семантического ядра;• размещение ключевых запросов на релевантных страницах, создание недостающих страниц под другие запросы;•
Стратегия продвижения
Стратегия продвижения Продвигать молодой сайт методами SEO на ранних стадиях сложно и долго, но это необходимо, чтобы достигнуть значительных успехов в дальнейшем и прочно «окопаться» в топе. В первые месяцы рекомендуется использовать только НЧ — запросы и продвигать
Цель и стратегия знакомства
Цель и стратегия знакомства Знакомство только на первый взгляд кажется простой и понятной вещью. Ведь каждый под этим словом понимает что-то свое…Знакомства «для трепа». В принципе, это тоже неплохо – всегда иметь под рукой некоторое число собеседников, с которыми можно
4.16. Стратегия резервного копирования
4.16. Стратегия резервного копирования Успешно, во всяком случае, я на это надеюсь, разобравшись с технической стороной создания резервных копий, переходим к организационным вопросам. А именно, вам нужно определиться с ответами на следующие вопросы:1. Какая информация
24.3 Стратегия безопасности
24.3 Стратегия безопасности Интеграция безопасности в IP стала одной из наиболее сложных работ, выполненных IETF. Аутентификация, целостность данных и конфиденциальность стали насущными и необходимыми. Стратегия безопасности предполагает:? Содействие совместной работе,
10.2. Стратегия резервного копирования
10.2. Стратегия резервного копирования Чтобы героически спасать файлы приходилось не слишком часто, следует заранее позаботиться об их надежной защите. Важнейшим средством защиты является резервное копирование.Вам нужно хорошо продумать следующие пункты:1. Какая
2. Представление графа списком инцидентности. Алгоритм обхода графа в глубину
2. Представление графа списком инцидентности. Алгоритм обхода графа в глубину Для реализации графа в виде списка инцидентности можно использовать следующий тип: Type List = ^S; S = record; inf : Byte; next : List; end; Тогда граф задается следующим образом: Var Gr : array[1..n] of List; Теперь обратимся к
«Классический» паттерн «Стратегия»
«Классический» паттерн «Стратегия» Если вас больше интересуют паттерны проектирования, чем собственно язык C++, то более традиционный подход к реализации паттерна «Стратегия» состоит в том, чтобы сделать функцию вычисления жизненной силы виртуальной функцией-членом в
Обход в ширину, симметричный обход и обход в глубину
Обход в ширину, симметричный обход и обход в глубину Прежде чем приступить к описанию остальных трех алгоритмов обхода, которые взаимосвязаны, приведем несколько иное определение бинарного дерева. Бинарное дерево состоит из корневого узла, содержащего указатели на
Стратегия покупки
Стратегия покупки Перво-наперво решите, какой из трех вариантов хотите купить (сумку, рюкзак или усиленный), из какого материала и готовы ли вы потратиться на бренд. Только после этого стоит смело отправляться искать нужное по Интернету и магазинам.И имейте в виду – к
Стратегия внедрения
Стратегия внедрения В этом разделе мы рассмотрим, какую стратегию должно освоить предприятие нового тысячелетия для проекта внедрения Системы ERP, «как товара на полках супермаркета».Внедрение модулей SAP по принципу «Большого взрыва»Организации стоит принять на
Стратегия и тактика
Стратегия и тактика С точки зрения системного администратора непроизводительной затратой времени является любое дело, которое можно было бы исключить, если бы нашлось время на создание инфраструктуры, позволяющей от этого дела отказаться. Иными словами, лучшим
Поверхностное мышление: как цифровые СМИиК снижают глубину обработки информации
Поверхностное мышление: как цифровые СМИиК снижают глубину обработки информации Чем более поверхностно я вникаю в суть поступившей информации, тем меньше синапсов будет активизировано в моем головном мозге, следовательно, и запомню я ее плохо. Понимание этого крайне
Глава 17. Стратегия проектирования
Глава 17. Стратегия проектирования Мы начнем с самого простого дизайна, который только возможен. После этого мы будем постоянно пересматривать дизайн системы. Мы будем удалять из системы любую гибкость, которая оказывается бесполезной.Во многих отношениях эта глава