
7.2. Перебор с возвратом
Опишем общий метод, позволяющий значительно сократить число шагов в алгоритмах типа полного перебора всех возможностей. Идея перебора с возвратом состоит в том, чтобы, начав с тривиального частичного решения, последовательно продолжать его до тех пор, пока не будет получено полное решение, либо продолжение станет невозможным. В последнем случае мы возвращаемся на шаг назад и пробуем построить другое продолжение. Если пространство поиска конечно, то либо мы получим полное решение, либо убедимся в невозможности его построения, поскольку осуществлен полный перебор возможных продолжений.
Чтобы применить этот метод, искомое решение должно иметь вид последовательности (a1, a2, ...,aN). Основная идея метода состоит в том, что мы строим решение последовательно, начиная с пустой последовательности e (длины 0). Вообще, имея данное частичное решение (a1, a2, ...,ai), мы стараемся найти такое допустимое значение ai+1, относительно которого мы не можем сразу заключить, что (a1, a2, ...,ai+1) можно расширить до некоторого решения (либо (a1, a2, ...,ai+1) уже является решением). Если такое предполагаемое, но еще не использованное решение ai+1 существует, то мы добавляем его к нашему частичному решению и продолжаем процесс для последовательности (a1, a2, ...,ai+1). Если его не существует, то мы возвращаемся к нашему частичному решению (a1, a2, ...,ai-1) и продолжаем наш процесс, отыскивая новое, еще не использованное допустимое значение ai' - отсюда название "алгоритм с возвратом" (англ. Backtracking).
Общая
схема[ ]. Даны
N
упорядоченных множеств U1,
U2,...,
UN
(N
- известно), и требуется построить
последовательность (вектор) А
= (а1,а2,
..., aN),
где a1U1,
a2
U2
,..., aN
UN,
удовлетворяющий заданному множеству
условий и ограничений.
В
алгоритме перебора последовательность
А
строится покомпонентно слева направо.
Предположим, что уже найдены значения
первых (k-1)
компонент, А=(
а1,а2,
..., ak-1
,?,.., ?), тогда заданное множество условий
ограничивает выбор следующей
компоненты
аk
некоторым множеством SkUk.
Если Sk
≠ [ ] (пустое), мы вправе выбрать в качестве
аk
наименьший элемент Sk
и перейти к выбору (k+1)
компоненты и так далее. Однако если
условия таковы, что Sk
оказалось пустым, то мы возвращаемся к
выбору (k-1)
компоненты, отбрасываем ak-1
и выбираем в качестве нового ak-1
тот элемент Sk-1
, который непосредственно следует
за только что отброшенным. Может
оказаться, что для нового ak-1
условия задачи допускают непустое
Sk
, и
тогда мы пытаемся снова выбрать элемент
аk.
Если невозможно выбрать аk-1,
мы возвращаемся еще на шаг назад и
выбираем новый элемент аk-2
и так далее.
В данном методе дерево как модель может использоваться не только как эффективная структура для представления данных, но и как абстракция для выражения процесса решения задачи – так называемое дерево решений. Метод проб и ошибок при переборе вариантов можно рассматривать в общем виде как поисковый процесс, который постепенно строит и просматривает дерево подзадач. Иными словами идея поиска с возвратами состоит в следующем. Находясь в некоторой ситуации, пробуем изменить ее в надежде найти решение. Если изменение не привело к успеху, то возвращаемся в исходную ситуацию (отсюда название «поиск с возвратами» ) и пробуем изменить ее другим образом, и так до тех пор, пока не будут исчерпаны все возможности.
Итак,
графическое изображение - дерево поиска.
Корень дерева (0 уровень) есть пустая
последовательность. Его сыновья суть
множество кандидатов для выбора а1
и, в общем случае, узлы k-го
уровня являются кандидатами на выбор
аk
при условии, что
а1,а2,
..., ak-1
выбраны так, как указывают предки этих
узлов. Вопрос в том, имеет ли задача
решение, равносилен вопросу, являются
ли какие-нибудь узлы дерева решениями.
Разыскивая все решения мы хотим
получить все такие узлы.
Обычно процесс проб и ошибок разделяется на отдельные подзадачи. Часто эти подзадачи наиболее естественно описываются с помощью рекурсии. Предмет этого раздела – общий принцип разбиения таких задач на подзадачи и использование в них рекурсии.
Рекурсивная схема реализации алгоритма:
Procedure Backtrack (последовательность, i );
Begin