Betrachten Sie einen Ausdruck 2^2^...^2
mit n
Operatoren ^
. Operator ^
bedeutet Potenzierung ("hoch"). Angenommen, es gibt keine Standardassoziativität, sodass der Ausdruck vollständig in Klammern gesetzt werden muss, um eindeutig zu werden. Die Anzahl der Möglichkeiten, den Ausdruck in Klammern zu setzen, wird durch katalanische Zahlen angegeben C_n=(2n)!/(n+1)!/n!
.
Manchmal führen unterschiedliche Klammern beispielsweise zu demselben numerischen Ergebnis, (2^2)^(2^2)=((2^2)^2)^2
sodass die Anzahl der unterschiedlichen möglichen numerischen Ergebnisse für eine bestimmte Zahl n
geringer ist als C_n
für alle anderen n>1
. Die Sequenz beginnt 1, 1, 2, 4, 8, ...
im Gegensatz zu katalanischen Zahlen1, 2, 5, 14, 42, ...
Das Problem besteht darin, das schnellste Programm (oder die schnellste Funktion) zu schreiben, das bzw. die n
als Eingabe akzeptiert und die Anzahl der verschiedenen möglichen numerischen Ergebnisse des Ausdrucks 2^2^...^2
mit n
Operatoren zurückgibt ^
. Die Leistung sollte sich mit zunehmender Leistung nicht wesentlich verschlechtern n
, daher ist die direkte Berechnung von Hochleistungstürmen wahrscheinlich eine schlechte Idee.
quelle
2^n
wird und es daher unnötig wäre, alles außer zu verfolgenn
. Das heißt, nur die Regeln der Potenzierung zu verwenden, scheint klug. Es gibt jedoch sicherlich eine intelligentere und vollständig algebraische Möglichkeit, dies zu tun.n
ist das wohl noch viel zu groß zum rechnen. Trotzdem gut bemerkt. Möglicherweise eine rekursive Darstellung in der Form "1 oder 2 ^ (...) oder (...) + (...)"; Sie haben jedoch immer noch das Problem, wie Sie eine solche Darstellung einer Zahl normalisieren (oder zwei Darstellungen auf Wertgleichheit vergleichen).n
zwei haben undC_n=(2n)!/(n+1)!/n!
die Anzahl der Klammern sein sollten, dann sollte es für n = 3 5 sein, richtig? Ich sehe(2^2)^2
und2^(2^2)
, aber was sind die anderen drei Kombinationen? Ich denke, C_n gibt Ihnen die Anzahl der Klammern für n + 1 Zweien.Antworten:
Python 2.7
Dieser Ansatz nutzt die folgenden Überlegungen:
Jede ganze Zahl kann als Summe von Zweierpotenzen dargestellt werden. Die Exponenten in Zweierpotenzen können auch als Zweierpotenzen dargestellt werden. Beispielsweise:
Diese Ausdrücke, mit denen wir enden, können als Mengen von Mengen dargestellt werden (in Python habe ich die eingebauten verwendet
frozenset
):0
wird die leere Menge{}
.2^a
wird die Menge, die die Menge darstellta
. ZB:1 = 2^0 -> {{}}
und2 = 2^(2^0) -> {{{}}}
.a+b
wird zur Verkettung der Mengen, diea
und darstellenb
. Z.B,3 = 2^(2^0) + 2^0 -> {{{}},{}}
Es stellt sich heraus, dass Ausdrücke des Formulars
2^2^...^2
leicht in ihre eindeutige Mengenrepräsentation umgewandelt werden können, selbst wenn der numerische Wert viel zu groß ist, um als Ganzzahl gespeichert zu werden.Für
n=20
läuft dies in 8.7s auf CPython 2.7.5 auf meinem Computer (etwas langsamer in Python 3 und viel langsamer in PyPy):(Das Konzept des Memoization Decorators wurde von http://code.activestate.com/recipes/578231-wahrscheinlich-der-schnellste-Memoization-Decorator-in- / kopiert .)
Ausgabe:
Timings für verschiedene
n
:Jegliche
n
über 21 führt zu einem Speicherfehler auf meinem Rechner.Es würde mich interessieren, ob jemand dies beschleunigen kann, indem er es in eine andere Sprache übersetzt.
Bearbeiten:
get_results
Funktion optimiert . Die Verwendung von Python 2.7.5 anstelle von 2.7.2 beschleunigte zudem die Ausführung.quelle
(a^b)^c = (a^c)^b
, und sie ist immer noch viel langsamer als diese Python-Implementierung.C #
Dies ist eine Übersetzung von Flornquakes Python-Code in C # unter Verwendung einer Additionsroutine auf niedrigerer Ebene, die eine moderate Beschleunigung gegenüber einer direkten Übersetzung bietet. Es ist nicht die optimierteste Version, die ich habe, aber das ist ziemlich viel länger, da es die Baumstruktur sowie die Werte speichern muss.
quelle