Ханойская башня (также называемый Башней Брахмы или Башней Лукаса и иногда во множественном числе Башни ) - это математическая игра или загадка. Он состоит из трех стержней и ряда дисков разного размера, которые могут надеваться на любую стержень. Головоломка начинается с дисков, расположенных аккуратной стопкой в порядке возрастания размера на одном стержне, наименьший наверху, образуя коническую форму.
Задача головоломки - переместить всю стопку на другой стержень, соблюдая следующие простые правила:
С 3 дисками головоломка решается за 7 ходов. Минимальное количество ходов, необходимых для решения загадки Ханойской башни, составляет 2-1, где n - количество дисков.
Головоломка была изобретена французским математиком Эдуардом Лукасом в 1883 году. Многочисленные мифы о древней и мистической природе головоломки возникли почти сразу. Существует история об индийском храме в Каши Вишванатх, в котором есть большая комната с тремя изношенными столбами в ней, окруженная 64 золотыми дисками. Брамины жрецы, выполняя приказ древнего пророчества, с тех пор перемещают эти диски в соответствии с неизменными правилами Брахмы. Поэтому загадка также известна как загадка Башня Брахмы. Согласно легенде, когда завершится последний ход головоломки, мир погибнет.
Если бы легенда была правдой и если бы жрецы могли перемещать диски со скоростью один в секунду, используя наименьшее количество ходов, которое им потребуется 2 - 1 секунда, или примерно 585 миллиардов лет, что примерно в 42 раза больше нынешнего возраста Вселенной.
Есть много вариантов этой легенды. Например, в некоторых рассказах храм - это монастырь, а священники - монахи. Можно сказать, что храм или монастырь находятся в разных частях мира, включая Ханой, Вьетнам, и могут быть связаны с любой религией. В некоторых версиях представлены другие элементы, такие как тот факт, что башня была создана в начале мира, или что священники или монахи могут делать только один ход в день.
В головоломку можно играть с любым количеством дисков, хотя во многих версиях игрушек их от 7 до 9. Минимальное количество ходов, необходимых для решения загадки Ханойской башни, составляет 2-1, где n - количество дисков. Это в точности n-е число Мерсенна.
Простым решением для игрушечной головоломки является чередование ходов между наименьшим кусочком и не- самый маленький кусочек. При перемещении самого маленького фрагмента всегда перемещайте его на следующую позицию в том же направлении (вправо, если начальное количество фрагментов четное, влево, если начальное количество фрагментов нечетное). Если в выбранном направлении нет позиции башни, переместите фигуру в противоположный конец, но затем продолжайте движение в правильном направлении. Например, если вы начали с трех частей, вы переместите самую маленькую часть на противоположный конец, а затем продолжите влево после этого. Когда наступает очередь переместить не самую маленькую фигуру, возможен только один ход. Выполнение этого завершит головоломку за наименьшее количество ходов.
Для четного числа дисков:
Для нечетного количества дисков:
В каждом случае в общей сложности выполняется 2–1 ход сделал.
Другой способ создания уникального оптимального итерационного решения:
Пронумеруйте диски от 1 до n (от наибольшего к наименьшему).
Теперь добавьте эти ограничения:
Учитывая эти ограничения после первого хода, на каждом последующем ходу есть только одно допустимое перемещение.
Последовательность этих уникальных ходов является оптимальным решением проблемы, эквивалентным итеративному решению, описанному выше.
Ключом к рекурсивному решению проблемы является осознание того, что ее можно разбить на набор более мелких подзадач, к каждой из которых применяется та же общая процедура решения, которую мы ищем, и общее решение затем найден простым способом из решений этих подзадач. Каждая из созданных таким образом подзадач «меньшего размера» гарантирует, что в конечном итоге будет достигнут базовый вариант (я). Отсюда для Ханойских башен:
Предполагается, что все n дисков распределены в допустимом порядке между штифтами; предполагая, что на исходной привязке есть m верхних дисков, а все остальные диски больше m, поэтому их можно безопасно игнорировать; для перемещения m дисков с исходной привязки на целевую привязку с использованием запасной привязки без нарушения правил:
Полное решение Tower of Hanoi состоит из перемещения n дисков с исходной привязки A на целевую привязку C, используя B в качестве запасной привязки.
Этому подходу может быть дано строгое математическое доказательство с помощью математической индукции, и он часто используется как пример рекурсии при обучении программированию.
Как и во многих математических головоломках, поиск решения упрощается путем решения немного более общей проблемы: как переместить башню из h (высотой) дисков из начальная привязка f = A (от) к целевой привязке t = C (до), B является оставшейся третьей привязкой и предполагается, что t ≠ f. Во-первых, обратите внимание, что проблема является симметричной для перестановок имен штифтов (симметрическая группа S 3 ). Если известно решение перехода от привязки A к привязке C, то, переименовав привязки, то же решение можно использовать для любого другого выбора начальной и конечной привязки. Если есть только один диск (или вообще нет), проблема тривиальна. Если h = 1, просто переместите диск с привязки A на привязку C . Если h>1, то где-то в последовательности перемещений самый большой диск должен быть перемещен с стержня A на другой стержень, предпочтительно на стержень C . Единственная ситуация, которая позволяет это перемещение, - это когда все меньшие диски h - 1 находятся на привязке B . Следовательно, сначала все диски меньшего размера h - 1 должны перейти с A на B . Затем переместите самый большой диск и, наконец, переместите h - 1 меньшие диски с привязки B на привязку C . Наличие самого большого диска не препятствует перемещению дисков меньшего размера h - 1 и может быть временно проигнорировано. Теперь проблема сводится к перемещению h - 1 дисков с одного стержня на другой, сначала с A на B, а затем с B на C, но оба раза можно использовать один и тот же метод, переименовав колышки. Эту же стратегию можно использовать для уменьшения задачи h - 1 до h - 2, h - 3 и так далее, пока не останется только один диск. Это называется рекурсией. Этот алгоритм можно схематически представить следующим образом.
Определите диски в порядке увеличения их размера натуральными числами от 0 до h, но не включая h. Следовательно, диск 0 - самый маленький, а диск h - 1 - самый большой.
Ниже приводится процедура перемещения колонны из h дисков с стержня A на стержень C, при этом B является оставшимся третья привязка:
с помощью математической индукцией, легко доказать, что описанная выше процедура требует минимально возможного количества ходов, и что полученное решение является единственным с таким минимальным количеством ходов. Используя рекуррентные отношения, точное количество ходов, которое требуется для этого решения, можно рассчитать по формуле: . Этот результат получается из того, что шаги 1 и 3 занимают ходов, а шаг 2 - один ход, что дает .
Следующий код Python выделяет важную функцию рекурсивного решения, которое иначе может быть неправильно понято или пропущено. То есть на каждом уровне рекурсии первый рекурсивный вызов инвертирует целевой и вспомогательный стеки, тогда как во втором рекурсивном вызове инвертируются исходный и вспомогательный стеки.
A = [3, 2, 1] B = C = def move (n, source, target, a secondary): if n>0: # Переместить n - 1 диск из источника во вспомогательный, чтобы они были вне way move (n - 1, source, a secondary, target) # Переместите n-й диск из источника в целевой target.append (source.pop ()) # Отобразите наш прогресс print (A, B, C, '##### ######### ', sep =' \ n ') # Переместите n - 1 дисков, которые мы оставили на вспомогательном перемещении, на целевое перемещение (n - 1, вспомогательное, целевое, исходное) # Инициируйте вызов от источника A для целевой C с помощью вспомогательного перемещения B (3, A, C, B)
Следующий код реализует больше рекурсивных функций для текстовой анимации:
время импорта A = [i for i in range (5, 0, -1)] height = len (A) - 1 # Стабильное значение высоты для анимации B = C = def move (n, source, target, a вспомогательный): if n>0: # Перемещение n - 1 диска из исходного во вспомогательный, поэтому они не мешают move (n - 1, source, a secondary, target) # Переместите n-й диск из источника в целевой target.append (source.pop ()) # Отобразите наш прогресс, используя рекурсивную функцию для его отрисовки из розыгрыша _disks (A, B, C, height) print ("") # Задайте интервал time.sleep (0.3) # Сделайте паузу для анимации # Переместите n - 1 дисков, которые мы оставили на вспомогательном перемещении, на целевое перемещение (n - 1, a secondary, target, source) def draw_disks (A, B, C, position, width = 2 * int (max (A))): # параметр ширины по умолчанию равен удвоению самого большого размера диска в начальной башне. if position>= 0: # Если A имеет значение в списке в данной позиции, создать диск в его позиции (высоте) valueInA = "" if position>= len (A) else create_disk (A [position]) # То же самое для B и C valueInB = "" if position>= len (B) else create_disk (B [position]) valueInC = "" if position>= len (C) else create_disk (C [position]) # Распечатать каждую строку print ("{0: ^ {width}} {1: ^ {width}} {2: ^ {width}}". Format (valueInA, valueInB, valueInC, width = width)) # Рекурсивно вызывать этот метод снова для следующего position (height) draw_disks (A, B, C, position - 1, width) else: # После выполнения с рекурсивным методом распечатайте метки столбцов print ("{0: ^ {width}} {1: ^ {width}} {2 : ^ {width}} ". format (" A "," B "," C ", width = width)) def create_disk (size):" "" Простой рекурсивный метод создания наклонного диска. "" "if size == 1: return "/ \\" else: return "/" + create_disk (size - 1) + "\\" # Инициировать вызов от источника A к цели C с помощью вспомогательного перемещения B (len (A), A, C, B)
Список ходов для несущей башни Перемещение с одного стержня на другой, как результат рекурсивного алгоритма, имеет много закономерностей. При подсчете ходов, начиная с 1, порядковый номер диска, который нужно переместить во время хода m, равен количеству раз, которое m можно разделить на 2. Следовательно, каждое нечетное движение включает в себя наименьший диск. Также можно заметить, что наименьший диск пересекает колышки f, t, r, f, t, r и т. Д. Для нечетной высоты башни и пересекает колышки f, r, t, f, r, t и т. Д. для ровной высоты башни. Это обеспечивает следующий алгоритм, который проще выполнять вручную, чем рекурсивный алгоритм.
Альтернативными перемещениями:
Для самый первый ход, наименьший диск попадает в привязку t, если h нечетно, и на привязку r, если h четно.
Также обратите внимание, что:
Обладая этим знанием, можно восстановить набор дисков в середине оптимального решения, имея не больше информации о состоянии, чем положение каждого диска:
Позиции диска могут быть определены более непосредственно из двоичного (base-2) представления номера хода (начальное состояние - перемещение # 0, со всеми цифрами 0 и Конечное состояние состоит из всех цифр 1), используя следующие правила:
Например, в 8-disk Hanoi:
Исходная и конечная привязки для m-го хода также могут быть элегантно найдены из двоичного представления m с помощью побитовых операций. Чтобы использовать синтаксис языка программирования C, переместите m из peg (m m - 1)% 3
в peg ((m | m - 1) + 1)% 3
, где диски начинаются на привязке 0 и заканчиваются на привязке 1 или 2 в зависимости от того, четное или нечетное количество дисков. Другая формулировка - от привязки (m - (m -m))% 3
до привязки (m + (m -m))% 3
.
Кроме того, диск, который нужно переместить определяется количеством раз, когда счетчик ходов (m) может быть разделен на 2 (т.е. количество нулевых битов справа), считая первый ход как 1 и идентифицируя диски числами 0, 1, 2 и т. д. в порядке увеличения размера. Это позволяет очень быстрой нерекурсивной компьютерной реализации находить положения дисков после m перемещений без ссылки на какое-либо предыдущее перемещение или распределение дисков.
Операция, которая подсчитывает количество последовательных нулей в конце двоичного числа, дает простое решение проблемы: диски нумеруются с нуля, а на шаге m число дисков count завершающие нули перемещаются на минимально возможное расстояние вправо (при необходимости возвращаясь влево).
Двоичная система счисления Грея коды дают альтернативный способ решения головоломки. В системе Грея числа выражаются в виде двоичной комбинации нулей и единиц, но вместо стандартной позиционной системы счисления, код Грея исходит из предпосылки, что каждое значение отличается от своего предшественника только на один ( и ровно один) бит поменял.
Если подсчитать в коде Грея размер бита, равный количеству дисков в конкретной Ханойской башне, начинается с нуля и подсчитывается, то бит, изменяемый при каждом перемещении, соответствует перемещаемому диску, где младший бит - это самый маленький диск, а самый старший бит - самый большой.
Этот метод определяет, какой диск переместить, но не указывает, куда его переместить. Для самого маленького диска всегда есть две возможности. Для других дисков всегда есть одна возможность, кроме случаев, когда все диски находятся на одной и той же привязке, но в этом случае либо это наименьший диск, который необходимо переместить, либо цель уже достигнута. К счастью, есть правило, которое говорит, куда переместить самый маленький диск. Пусть f - начальная привязка, t - привязка назначения, а r - оставшаяся третья привязка. Если количество дисков нечетное, наименьший диск движется по колышкам в порядке f → t → r → f → t → r и т. Д. Если количество дисков четное, это должно быть отменено: f → r → t → f → r → t и т. Д.
Положение изменения бита в решении кода Грея дает размер диска, перемещаемого на каждом шаге: 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1,... (последовательность A001511 в OEIS ), последовательность, также известная как линейка функция, или на единицу больше, чем степень двойки в номере хода. В Wolfram Language, IntegerExponent [Range [2 ^ 8-1], 2] + 1
дает ходы для головоломки с 8 дисками.
Игра может быть представлена неориентированным графом, узлы которого представляют собой распределения дисков, а ребра представляют собой ходы. Для одного диска график представляет собой треугольник:
График для двух дисков представляет собой три треугольника, соединенных между собой, образуя углы большего треугольника.
Вторая буква добавляется для обозначения большего диска. Ясно, что изначально его нельзя переместить.
Самый верхний маленький треугольник теперь представляет возможности за один ход с двумя дисками:
Узлы в вершинах крайнего треугольника представляют распределения со всеми дисками на одной и той же привязке.
Для h + 1 дисков возьмите график из h дисков и замените каждый маленький треугольник графиком для двух дисков.
Для трех дисков график выглядит следующим образом:
Стороны самого крайнего треугольник представляют собой кратчайшие пути перемещения башни с одного колышка на другой. Ребро в середине сторон самого большого треугольника представляет собой движение самого большого диска. Ребро в середине сторон каждого следующего меньшего треугольника представляет собой перемещение каждого следующего меньшего диска. Стороны самого маленького треугольника представляют собой движения самого маленького диска.
Игровой график уровня 7 показывает связь с треугольником Серпинского.В общем, для головоломки с n дисками в графе 3 узлов; каждый узел имеет три ребра по отношению к другим узлам, за исключением трех угловых узлов, которые имеют два: всегда можно переместить наименьший диск на один из двух других колышков, и можно переместить один диск между этими двумя колышками, за исключением ситуация, когда все диски уложены на одном колышке. Угловые узлы представляют три случая, когда все диски уложены на одном стержне. Диаграмма для n + 1 дисков получается путем взятия трех копий диаграммы из n дисков, каждая из которых представляет все состояния и перемещения меньших дисков для одной конкретной позиции нового самого большого диска, и соединения их по углам тремя новые грани, представляющие только три возможности переместить самый большой диск. Таким образом, получившаяся фигура имеет 3 узла и по-прежнему имеет три угла и только два ребра.
По мере добавления дисков графическое представление игры будет напоминать фрактальную фигуру, треугольник Серпинского. Ясно, что подавляющее большинство позиций в головоломке никогда не будут достигнуты при использовании кратчайшего возможного решения; действительно, если жрецы легенды используют максимально долгое решение (без повторного посещения какой-либо позиции), им потребуется 3–1 ход или более 10 лет.
Самый длинный неповторяющийся путь для трех дисков можно визуализировать, стирая неиспользуемые края:
Между прочим, этот самый длинный неповторяющийся путь может быть получен путем запрета всех перемещений от a к b.
Гамильтонов цикл для трех дисков:
Графики ясно показывают, что:
Это дает N h равным 2, 12, 1872, 6563711232,... (последовательность A125295 в OEIS )
Если все перемещения должны быть между соседними колышками (т. Е. Заданы колышки A, B, C, нельзя перемещаться напрямую между колышками A и C), тогда для перемещения стопки из n дисков с колышка A на колышек C требуется 3–1 ход. Решение использует все 3 допустимые позиции, всегда выполняя уникальный ход который не отменяет предыдущий ход. Положение со всеми дисками на привязке B достигается на полпути, то есть после (3 - 1) / 2 ходов.
В Cyclic Hanoi мы даны три колышка (A, B, C), которые расположены в виде круга с направлениями по часовой стрелке и против часовой стрелки, определяемыми как A - B - C - A и A - C - B - A соответственно. Направление движения диск должен быть повернут по часовой стрелке. Достаточно представить последовательность перемещаемых дисков. Решение может быть найдено с помощью двух взаимно рекурсивных процедур:
Чтобы переместить n дисков против часовой стрелки на соседнюю целевую привязку:
Чтобы переместить n дисков по часовой стрелке на соседнюю целевую привязку:
Пусть C (n) и A (n) представляют перемещение n дисков по часовой стрелке и против часовой стрелки, то мы можем записать обе формулы:
C (n) = A (n-1) n A (n-1) и A (n) = A (n-1) n C (n-1) n A (n-1).
Таким образом, C (1) = 1 и A (1) = 1 1, C (2) = 1 1 2 1 1 и A (2) = 1 1 2 1 2 1 1.
Решение для циклического Ханоя имеет несколько интересных свойств:
1) Шаблоны перемещений при перемещении башни дисков с колышка на другой колышек симметричны относительно центральных точек.
2) Самый маленький диск - это первый и последний диск, который нужно переместить.
3) Группы наименьших перемещений диска чередуются с одиночными перемещениями других дисков.
4) Количество перемещений дисков, заданное C (n) и A (n), минимально.
Хотя версия с тремя колышками имеет простое рекурсивное решение, давно известное, оптимальным решением проблемы Ханойской башни с четырьмя колышками (так называемая головоломка Рива) было не проверено Бушем до 2014 года.
Однако в случае четырех или более привязок алгоритм Фрейма – Стюарта известен без доказательства оптимальности с 1941 года.
Для формального вывода точное количество минимальных ходов, необходимых для решения проблемы с помощью алгоритма Фрейма – Стюарта (и других эквивалентных методов), см. в следующей статье.
Для других вариантов задачи Ханойской башни с четырьмя колышками см. Paul Обзорная статья Стокмейера.
Алгоритм Фрейма – Стюарта описан ниже:
Алгоритм можно описать рекурсивно:
Весь процесс занимает
Этот алгоритм (с указанным выше выбором для
Любопытное обобщение исходной цели головоломки - начать с заданной конфигурации дисков, когда все диски не обязательно находятся на одном и том же привязка, и прийти за минимальное количество ходов в другую заданную конфигурацию. В общем, может быть довольно сложно вычислить кратчайшую последовательность ходов для решения этой проблемы. Решение было предложено Андреасом Хинцем и основано на наблюдении, что в кратчайшей последовательности перемещений нужно переместить самый большой диск (очевидно, можно игнорировать все самые большие диски, которые будут занимать одну и ту же точку в обоих начальных и окончательные конфигурации) переместятся либо ровно один раз, либо ровно дважды.
Математика, связанная с этой обобщенной проблемой, становится еще более интересной, если учесть среднее количество ходов в кратчайшей последовательности ходов между двумя начальными и конечными конфигурациями диска, которые выбираются случайным образом. Хинц и Чан Тат-Хунг независимо друг от друга обнаружили (см. Также), что среднее число ходов в башне из n дисков определяется следующей точной формулой:
Для достаточно большого n, только первый и второй члены не сходятся к нулю, поэтому мы получаем асимптотическое выражение :
In Magnetic Tower В Ханое каждый диск имеет две отдельные стороны - север и юг (обычно окрашенные в красный и синий цвета). Диски нельзя ставить одинаковыми полюсами вместе - магниты в каждом диске предотвращают это незаконное перемещение. Кроме того, каждый диск необходимо переворачивать при перемещении.
Первоначальная конфигурация двухцветных башен Ханоя (n = 4)Этот вариант знаменитой головоломки Ханойская башня был предложен ученикам 3–6 классов в 2ème Championnat de France des Jeux Mathématiques et Logiques, состоявшаяся в июле 1988 года.
Окончательная конфигурация двухцветных башен Ханоя (n = 4)Правила головоломки в основном те же: диски перемещаются между колышками по одному. Ни в коем случае нельзя ставить больший диск поверх меньшего. Разница в том, что теперь для каждого размера есть два диска: черный и белый. Кроме того, теперь есть две башни из дисков чередующихся цветов. Цель головоломки - сделать башни одноцветными (одного цвета). Предполагается, что самые большие диски в нижней части башен поменяются местами.
Вариант головоломки был адаптирован как пасьянс с девятью игральными картами под названием Ханойская башня. Неизвестно, является ли измененное написание оригинального названия преднамеренным или случайным.
Чжан и