Considérons une expression 2^2^...^2
avec des n
opérateurs ^
. Opérateur ^
signifie exponentiation ("au pouvoir de"). Supposons qu'il n'y ait pas d'assosivité par défaut, donc l'expression doit être entièrement entre parenthèses pour devenir sans ambiguïté. Le nombre de façons de mettre l'expression entre parenthèses est donné par des nombres catalans C_n=(2n)!/(n+1)!/n!
.
Parfois, des parenthèses différentes donnent le même résultat numérique, par exemple (2^2)^(2^2)=((2^2)^2)^2
, de sorte que le nombre de différents résultats numériques possibles pour un donné n
est inférieur à celui C_n
de tous n>1
. La séquence commence 1, 1, 2, 4, 8, ...
par opposition aux nombres catalans1, 2, 5, 14, 42, ...
Le problème est d'écrire le programme (ou la fonction) le plus rapide qui accepte n
en entrée et renvoie le nombre de résultats numériques différents possibles de l'expression 2^2^...^2
avec des n
opérateurs ^
. Les performances ne devraient pas se détériorer de manière significative au fur et à mesure de leur n
croissance, donc le calcul direct des tours de forte puissance est probablement une mauvaise idée.
la source
2^n
, et il serait donc inutile de garder une trace de tout saufn
. C'est-à-dire, le simple fait d'utiliser les règles d'exponentiation semble sage. Cependant, il existe certainement une manière plus intelligente et complètement algébrique de le faire.n
c'est encore beaucoup trop gros pour être calculé. Pourtant, bien noté. Peut-être une représentation récursive sous la forme "1 ou 2 ^ (...) ou (...) + (...)"; mais vous avez toujours le problème de normaliser une telle représentation d'un nombre (ou de comparer deux représentations pour l'égalité des valeurs).n
deux etC_n=(2n)!/(n+1)!/n!
que le nombre de parenthèses doit être égal, alors pour n = 3, il doit être égal à 5, n'est-ce pas? Je vois(2^2)^2
et2^(2^2)
, mais quelles sont les trois autres combinaisons? Je pense que C_n vous donne le nombre de parenthèses pour n + 1 deux.Réponses:
Python 2.7
Cette approche tire parti des considérations suivantes:
Tout entier peut être représenté comme une somme de puissances de deux. Les exposants aux pouvoirs de deux peuvent également être représentés comme des pouvoirs de deux. Par exemple:
Ces expressions avec lesquelles nous nous retrouvons peuvent être représentées comme des ensembles d'ensembles (en Python, j'ai utilisé le intégré
frozenset
):0
devient l'ensemble vide{}
.2^a
devient l'ensemble contenant l'ensemble représentanta
. Par exemple:1 = 2^0 -> {{}}
et2 = 2^(2^0) -> {{{}}}
.a+b
devient la concaténation des ensembles représentanta
etb
. Par exemple,3 = 2^(2^0) + 2^0 -> {{{}},{}}
Il s'avère que les expressions du formulaire
2^2^...^2
peuvent facilement être transformées en leur représentation d'ensemble unique, même lorsque la valeur numérique est beaucoup trop grande pour être stockée sous forme d'entier.Pour
n=20
, cela s'exécute en 8.7s sur CPython 2.7.5 sur ma machine (un peu plus lent en Python 3 et beaucoup plus lent en PyPy):(Le concept du décorateur de mémorisation est copié à partir de http://code.activestate.com/recipes/578231-probably-the-fastest-memoization-decorator-in-the-/ .)
Production:
Timings pour différents
n
:Toute valeur
n
supérieure à 21 entraîne une erreur de mémoire sur ma machine.Je serais intéressé si quelqu'un pouvait rendre cela plus rapide en le traduisant dans une autre langue.
Edit: optimisé la
get_results
fonction. En outre, l'utilisation de Python 2.7.5 au lieu de 2.7.2 l'a rendu un peu plus rapide.la source
(a^b)^c = (a^c)^b
, et c'est toujours beaucoup plus lent que cette implémentation Python.C #
Il s'agit d'une traduction du code Python de flornquake en C # en utilisant une routine d'ajout de niveau inférieur qui fournit une accélération modérée par rapport à une traduction directe. Ce n'est pas la version la plus optimisée que j'ai, mais c'est un peu plus long car il doit stocker la structure arborescente ainsi que les valeurs.
la source