Рассмотрим выражение 2^2^...^2
с n
операторами ^
. Оператор ^
означает возведение в степень («во власть»). Предположим, что он не имеет ассоциативности по умолчанию, поэтому выражение должно быть заключено в круглые скобки, чтобы стать однозначным. Количество способов заключить выражение в скобки даны каталонскими числами C_n=(2n)!/(n+1)!/n!
.
Иногда различные круглые скобки дают один и тот же числовой результат, например (2^2)^(2^2)=((2^2)^2)^2
, поэтому число различных возможных числовых результатов для данного n
меньше, чем C_n
для всех n>1
. Последовательность начинается 1, 1, 2, 4, 8, ...
в отличие от каталонских чисел1, 2, 5, 14, 42, ...
Проблема состоит в том, чтобы написать самую быструю программу (или функцию), которая принимает n
в качестве входных данных и возвращает число различных возможных числовых результатов выражения 2^2^...^2
с n
операторами ^
. Производительность не должна значительно ухудшаться по мере n
роста, поэтому прямой расчет мощных вышек, вероятно, является плохой идеей.
источник
2^n
, и поэтому нет необходимости отслеживать что-либо кромеn
. Т.е. просто использование правил возведения в степень кажется разумным. Тем не менее, безусловно, есть более умный и полностью алгебраический способ сделать это.n
он все еще слишком велик для вычислений. Тем не менее, хорошо отмечено. Может быть, рекурсивное представление в форме "1 или 2 ^ (...) или (...) + (...)"; но у вас все еще есть проблема, как нормализовать такое представление числа (или сравнить два представления для равенства значения).n
двойки иC_n=(2n)!/(n+1)!/n!
должно быть количество скобок, то для n = 3 это должно быть 5, правильно? Я вижу(2^2)^2
и2^(2^2)
, но каковы другие три комбинации? Я думаю, что C_n дает вам количество скобок для n + 1 двойки.Ответы:
Python 2.7
Этот подход использует следующие соображения:
Любое целое число может быть представлено как сумма степеней двух. Показатели в степени двух могут также быть представлены как степени двух. Например:
Эти выражения, которые мы заканчиваем, могут быть представлены как наборы множеств (в Python я использовал встроенный
frozenset
):0
становится пустым набором{}
.2^a
становится набором, содержащим набор, представляющийa
. Например:1 = 2^0 -> {{}}
и2 = 2^(2^0) -> {{{}}}
.a+b
становится объединением множеств, представляющихa
иb
. Например,3 = 2^(2^0) + 2^0 -> {{{}},{}}
Оказывается, что выражения формы
2^2^...^2
можно легко преобразовать в их уникальное представление набора, даже когда числовое значение слишком велико, чтобы его можно было сохранить как целое число.Для
n=20
, это работает в 8.7s на CPython 2.7.5 на моей машине (немного медленнее в Python 3 и намного медленнее в PyPy):(Концепция декоратора памятки скопирована с http://code.activestate.com/recipes/578231-probbly-the-fastest-memoization-decorator-in-the-/ .)
Выход:
Сроки для разных
n
:Любое значение
n
выше 21 приводит к ошибке памяти на моей машине.Мне было бы интересно, если бы кто-нибудь мог сделать это быстрее, переведя это на другой язык.
Редактировать: Оптимизирована
get_results
функция. Кроме того, использование Python 2.7.5 вместо 2.7.2 заставило его работать немного быстрее.источник
(a^b)^c = (a^c)^b
, и оно все еще намного медленнее, чем эта реализация Python.C #
Это перевод кода Python flornquake на C # с использованием процедуры добавления более низкого уровня, которая обеспечивает умеренное ускорение по сравнению с прямым переводом. Это не самая оптимизированная версия, которая у меня есть, но она немного длиннее, потому что она должна хранить как древовидную структуру, так и значения.
источник