8.6 KiB
Задача о Ханойских башнях
В сортировке слиянием и построении двоичного дерева мы разбиваем исходную задачу на две подзадачи, размер которых составляет половину исходной задачи. Однако для задачи о Ханойских башнях мы используем другую стратегию разбиения.
!!! question
Даны три стержня, обозначенные как `A`, `B` и `C`. В начальном состоянии на стержне `A` находится $n$ дисков, расположенных сверху вниз в порядке возрастания размера. Наша задача -- переместить эти $n$ дисков на стержень `C`, сохранив их исходный порядок (как показано на рисунке ниже). При перемещении дисков необходимо соблюдать следующие правила.
1. Диск можно снять только с верхушки одного стержня и поместить на верхушку другого стержня.
2. За один раз можно переместить только один диск.
3. Меньший диск всегда должен находиться над большим диском.
Обозначим задачу о Ханойских башнях размера i как $f(i)$. Например, f(3) представляет задачу о Ханойских башнях по перемещению 3 дисков с A на C.
Рассмотрение базового случая
Как показано на рисунке ниже, для задачи f(1), то есть когда имеется только один диск, мы можем просто переместить его с A на C.
Как показано на рисунке ниже, для задачи f(2), то есть когда имеется два диска, поскольку необходимо всегда соблюдать условие, что меньший диск находится над большим, нужно использовать B для завершения перемещения.
- Сначала переместить верхний меньший диск с
AнаB. - Затем переместить больший диск с
AнаC. - Наконец, переместить меньший диск с
BнаC.
Процесс решения задачи f(2) можно обобщить следующим образом: переместить два диска с A на C, используя B. При этом C называется целевым стержнем, а B -- буферным стержнем.
Разбиение на подзадачи
Для задачи f(3), то есть когда имеется три диска, ситуация становится немного сложнее.
Поскольку решения f(1) и f(2) уже известны, мы можем мыслить с точки зрения стратегии «разделяй и властвуй», рассматривая два верхних диска на A как единое целое, и выполнить шаги, показанные на рисунке ниже. Таким образом, три диска успешно перемещаются с A на C.
- Сделать
Bцелевым стержнем, аC-- буферным стержнем, и переместить два диска сAнаB. - Переместить оставшийся один диск с
Aнепосредственно наC. - Сделать
Cцелевым стержнем, аA-- буферным стержнем, и переместить два диска сBнаC.
По сути, мы разбиваем задачу f(3) на две подзадачи f(2) и одну подзадачу $f(1)$. После последовательного решения этих трех подзадач исходная задача также решается. Это показывает, что подзадачи независимы, и их решения можно объединить.
Таким образом, мы можем обобщить стратегию «разделяй и властвуй» для решения задачи о Ханойских башнях, показанную на рисунке ниже: разбить исходную задачу f(n) на две подзадачи f(n-1) и одну подзадачу f(1), и решить эти три подзадачи в следующем порядке.
- Переместить
n-1дисков сAнаB, используяC. - Переместить оставшийся
1диск непосредственно сAнаC. - Переместить
n-1дисков сBнаC, используяA.
Для этих двух подзадач f(n-1) можно применить рекурсивное разбиение тем же способом, пока не будет достигнута наименьшая подзадача f(1). А решение f(1) известно -- требуется только одна операция перемещения.
Реализация кода
В коде мы объявляем рекурсивную функцию dfs(i, src, buf, tar), которая перемещает i дисков с верхушки стержня src на целевой стержень tar, используя буферный стержень buf:
[file]{hanota}-[class]{}-[func]{solve_hanota}
Как показано на рисунке ниже, задача о Ханойских башнях формирует рекурсивное дерево высотой n, где каждый узел представляет подзадачу, соответствующую вызову функции dfs(), поэтому временная сложность составляет O(2^n), а пространственная сложность -- $O(n)$.
!!! quote
Задача о Ханойских башнях происходит из древней легенды. В храме в древней Индии у монахов было три высоких алмазных стержня и $64$ золотых диска разного размера. Монахи постоянно перемещали диски, веря, что в тот момент, когда последний диск будет правильно размещен, этот мир закончится.
Однако, даже если монахи будут перемещать диски каждую секунду, потребуется примерно $2^{64} \approx 1.84×10^{19}$ секунд, что составляет около $5850$ миллиардов лет, что намного превышает текущую оценку возраста Вселенной. Поэтому, если эта легенда правдива, нам не стоит беспокоиться о конце света.












