1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6

# конспект · шаг 6 из 6

Конспект: поиск с возвратом и отсечения

выжимка - её можно унести в заметки

Понятия

Поиск с возвратом - перебор по дереву вариантов, в котором допустимость ЧАСТИЧНОГО решения проверяется на входе в ветку; недопустимая ветка не раскрывается.

Откат - восстановление состояния после возврата из рекурсии. Пара к занятию ресурса, как закрывающая скобка к открывающей.

Отсечение - условие, при котором ветка не раскрывается. Три вида: по допустимости, по оценке, по симметрии.

Допустимая оценка - оценка лучшего в ветке, которая никогда не обещает меньше, чем ветка способна дать: для максимума не меньше, для минимума не больше.

Встреча посередине - разрезать вход пополам, перебрать половины отдельно (2^(n/2) вариантов каждая) и склеить частичные результаты по одному соотношению.

Что унести

СХЕМА ОДНОГО УРОВНЯ (повторяется от задачи к задаче)
  для каждого кандидата:
      1. проверить совместимость с принятыми решениями   ← вся экономия здесь
      2. занять ресурс
      3. спуститься
      4. ОТКАТИТЬ занятое                                ← вся надёжность здесь
восемь ферзей, ответ везде 92 узлов шагов
перебор всех клеток, проверка на дне 19 173 961 не уложился
перебор перестановок, проверка на дне 109 601 не уложился
поиск с возвратом 2 057 101 172
он же + симметрия (половина первой строки) 1 029 52 577

Отсечение на глубине k экономит всё поддерево продолжений - (n−k)! или nⁿ⁻ᵏ листьев. Поэтому проверять надо как можно раньше, а не как удобнее.

ТРИ ВИДА ОТСЕЧЕНИЙ
по допустимости   кандидат противоречит принятым решениям       надёжно, просто
по оценке         в ветке не может быть ответа лучше рекорда    сильнее всего
по симметрии      ветка - зеркало уже рассмотренной             постоянный множитель

ПОРЯДОК КАНДИДАТОВ отсечением не является, но решает, когда отсечения сработают
СУММА ПОДМНОЖЕСТВА, 20 чисел, цель 97 (ответ 179 во всех строках)
полное дерево                     2 097 151 узел   не уложился
+ превышение (summa > cel)           18 661 узел    73 126 шагов
+ остаток (summa + hvost[i] < cel)   15 017 узлов   62 684 шага
+ сортировка по УБЫВАНИЮ               6 047 узлов   25 996 шагов   в 347 раз меньше
сортировка по возрастанию            51 615 узлов  210 830 шагов   в 8 раз хуже
ВСТРЕЧА ПОСЕРЕДИНЕ - единственный приём, меняющий ПОКАЗАТЕЛЬ
2^n → 2^(n/2):  посильное n удваивается, с ~20 до ~40
суммы половины считать НАРАЩИВАНИЕМ (список удваивается на каждом элементе),
    а не перебором масок - разница в пять раз на замере
«ровно столько»  → словарь со счётчиком (множество занижает ответ)
«как можно ближе»→ сортировка + двоичный поиск или два указателя
плата - память 2^(n/2); она же и ставит границу приёма
делить ровно пополам: 8 и 16 вместо 12 и 12 - это 65 792 вместо 8192
n цель перебор с отсечениями встреча посередине
16 половина суммы 247 012 шагов 4 894 шага
20 половина суммы не уложился 20 170 шагов
20 лёгкая (97) 62 684 шага 18 444 шага
24 половина суммы не уложился 81 550 шагов

Цена отсечений зависит от данных целиком, цена встречи посередине - почти не зависит. Отсечения - первый ход, потому что дёшевы и не требуют памяти; встреча посередине - когда нужна гарантия.

Ловушки джокера

Забыл откат. Шесть ферзей дают ноль решений вместо четырёх, и программа не жалуется. Перебор при этом становится ДЕШЕВЛЕ (302 шага вместо 6176) - ложная занятость отсекает почти всё.

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

«Элемент не влезает - значит и ветка мертва». Не мертва: следующие элементы могут быть меньше. Пропускать надо кандидата, а не ветку.

Симметрия без точного счёта кратности. Девять ферзей: 298 (половина без центра × 2) или 406 (половина с центром × 2) вместо 352. Центральный столбец сам себе зеркало, его решения прибавляются один раз: 2 × 149 + 54 = 352. На чётном n ошибка не проявляется.

Отсечение, опирающееся на знак данных, без оговорки. summa > cel верно только для положительных чисел. Условие применимости писать рядом комментарием.

Остаток, посчитанный внутри рекурсии. Проверка станет стоить O(n) на узел и не окупится. Хвостовые суммы считаются один раз до перебора.

Разрезать задачу, в которой половины зависимы. Встреча посередине требует, чтобы частичный результат половины записывался одним числом, а склейка была равенством или сравнением. Для маршрута или порядка через все данные это не так.

Множество вместо словаря со счётчиком. Отвечает на «существует ли», а не на «сколько»: разные подмножества с равной суммой склеиваются в одно.

Ждать, что поиск с возвратом снимет экспоненту. Он сдвигает границу: десять ферзей - 2,1 миллиона шагов, одиннадцать - 10,9 миллиона.

Куда это ведёт

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

Комментарии

Пока нет комментариев. Будь первым!

Оставить комментарий

Комментарий появится после проверки. Email не публикуется. Войти, чтобы не вводить имя каждый раз.