Обход дерева. Перебор с возвратами
3.1. Ферзи, не бьющие друг друга: обход дерева позиций
В предыдущей лекции мы рассматривали несколько задач одного
и того же типа: "перечислить все элементы некоторого
множества ". Схема решения была такова: на
множестве
вводился порядок и описывалась процедура перехода от произвольного элемента множества
к следующему за ним (в этом порядке). Такую схему не всегда удается реализовать непосредственно, и в этой лекции мы
рассмотрим другой полезный прием перечисления всех
элементов некоторого множества. Его называют " поиск
с возвратами ", " метод ветвей и границ ", " backtracking ". На наш взгляд, наиболее точное название этого метода - обход дерева.
3.1.1.Перечислить все способы расстановки ферзей на шахматной
доске
, при которых они не бьют друг друга.
Решение. Очевидно, на каждой из горизонталей должно
стоять по ферзю. Будем называть k-позицией (для
) произвольную расстановку
ферзей на
нижних горизонталях (ферзи могут бить друг друга).
Нарисуем "дерево позиций": его корнем будет
единственная
-позиция, а из каждой
-позиции выходит
стрелок вверх в
-позиции. Эти
позиций отличаются положением ферзя на
-ой горизонтали. Будем считать, что расположение их на рисунке соответствует положению этого ферзя: левее та позиция, в которой ферзь расположен левее.
Среди позиций этого дерева нам надо отобрать те -позиции, в которых ферзи не бьют друг друга.
Программа будет "обходить дерево" и искать их.
Чтобы не делать лишней работы, заметим вот что: если
в какой-то
-позиции ферзи бьют друг друга, то
ставить дальнейших ферзей смысла нет. Поэтому, обнаружив
это, мы будем прекращать построение дерева в этом
направлении.
Точнее, назовем -позицию допустимой, если
после удаления верхнего ферзя оставшиеся не бьют
друг друга. Наша программа будет рассматривать только
допустимые позиции.