Einführung
Es gibt einen Steuereintreiber, der Schwierigkeiten hat, die Steuern seines Königreichs zu verwalten: Die historischen Aufzeichnungen sind in einem großen Feuer niedergebrannt.
Er möchte herausfinden, wie viele mögliche Vergangenheiten es geben könnte, woher das aktuelle Geld stammt. Zum Glück ist sein Königreich sehr einfach.
Das Königreich kann durch eine 2D-Boolesche Matrix modelliert werden, l
die jemanden darstellt, der Geld geerbt hat, und O
jemanden darstellt, der dies nicht getan hat. Beispielsweise:
l O l l
O O O l
l O l O
O O O l
(Es wird immer ein Rechteck sein)
In der nächsten Generation ist das Königreich kleiner (Die Wölfe sind stark!).
Die nächste Generation würde so aussehen, überlagert die vorherige Generation ( x
ist ein Platzhalter für einen Nachkommen in der nächsten Generation).
l O l l
x x x
O O O l
x x x
l O l O
x x x
O O O l
Ein Nachkomme an den Vorfahren sucht, die direkt um sie herum sind (also oben links x
sehen { l
, O
, O
, O
}, eine genannter Unaligned rechteckige Nachbarschaft )
Wenn nur ein Vorfahr Geld geerbt hat, erbt der Nachkomme Geld von ihnen. Wenn mehr als ein Vorfahr Geld geerbt hat, streiten sie sich und der Nachkomme erbt kein Geld. Wenn niemand Geld geerbt hat, erbt der Nachkomme kein Geld.
(Mehr als ein Nachkomme kann von einem Vorfahren erben)
Die nächste Generation würde also so aussehen:
l l O
l l O
l l O
Herausforderung
Eingang
Der aktuelle Status der Generation als Array von Arrays mit zwei unterschiedlichen Werten, wobei die inneren Arrays alle dieselbe Länge haben.
Für das obige Beispiel könnte es beispielsweise sein:
[
[True, True, False],
[True, True, False],
[True, True, False]
]
Ausgabe
Eine Ganzzahl, die die Anzahl der eindeutigen vorherigen Generationen darstellt, wobei die nächste Generation die Eingabe ist.
Sie können davon ausgehen, dass die Antwort immer kleiner als 2 ^ 30 - 1 ist (oder 1073741823).
Die vorherige Generation würde als "Vorbild" bezeichnet, und diese Herausforderung würde darin bestehen, die Vorbilder zu zählen .
Wertung
Dies ist eine Herausforderung mit dem schnellsten Code. Daher wird jede Einreichung auf meinem Computer getestet, und die Einreichung, die am wenigsten Zeit in Anspruch nimmt, ist der Gewinner.
Beispiel für Ein- und Ausgabe
(Wo 1
ist ein Nachkomme, der Geld geerbt hat, und 0
ein Nachkomme, der kein Geld geerbt hat?)
Eingang:
[[1, 0, 1],
[0, 1, 0],
[1, 0, 1]]
Ausgabe:
4
Eingang:
[[1, 0, 1, 0, 0, 1, 1, 1],
[1, 0, 1, 0, 0, 0, 1, 0],
[1, 1, 1, 0, 0, 0, 1, 0],
[1, 0, 1, 0, 0, 0, 1, 0],
[1, 0, 1, 0, 0, 1, 1, 1]]
Ausgabe:
254
Eingang:
[[1, 1, 0, 1, 0, 1, 0, 1, 1, 0],
[1, 1, 0, 0, 0, 0, 1, 1, 1, 0],
[1, 1, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 1, 0, 0, 0, 0, 1, 1, 0, 0]]
Ausgabe:
11567
quelle
Antworten:
C ++ mit der BuDDy-Bibliothek
Dies schien eine gute Ausrede zu sein, um mit binären Entscheidungsdiagrammen zu spielen . Das Königreich wird in eine große boolesche Formel umgewandelt, in der wir die Anzahl der Möglichkeiten zählen müssen, wie es erfüllt werden kann. Das kann (manchmal) effizienter gemacht werden, als es sich anhört.
Das Königreich muss als Programmkonstante als flaches Array und explizit vorgegebene Dimensionen angegeben werden. (Netter Input bleibt als Execise für den Leser :-)
Hier ist der peinlich einfache Code:
Zum Kompilieren mit Debian 8 (Jessie) installieren
libbdd-dev
und ausführeng++ -std=c++11 -o hist hist.cpp -lbdd
. (Optimierungsoptionen machen fast keinen Unterschied, da die eigentliche Arbeit in der Bibliothek erledigt wird.)Große Beispiele können zu Nachrichten über die Speicherbereinigung führen. Sie könnten unterdrückt werden, aber ich sehe sie lieber.
bdd_satcount
gibt a zurückdouble
, aber das ist gut genug für den erwarteten Ergebnisbereich. Die gleiche Zähltechnik ist mit exakten (großen) ganzen Zahlen möglich.Der Code ist optimiert für
ROWS<COLS
. Wenn Sie viel mehr Zeilen als Spalten haben, ist es möglicherweise eine gute Idee, die Matrix zu transponieren.quelle
Python 2.7
Dies ist nur ein naiver erster Versuch. Es ist nicht besonders schnell, aber es ist richtig.
Die erste Beobachtung ist, dass jede Zelle von genau vier Zellen der vorherigen Generation abhängig ist. Wir können diese vier Zellen als 4-Bit-Zahl (0-15) darstellen. Gemäß den Regeln ist
1
eine bestimmte Zelle in der aktuellen Generation , wenn genau eine benachbarte Zelle in der vorherigen Generation vorhanden ist1
, andernfalls0
. Diese entsprechen den Potenzen von zwei, nämlich[1, 2, 4, 8]
. Wenn die vier Vorfahren als 4-Bit-Zahl dargestellt werden, führt jede andere Zahl zu einer0
in der aktuellen Generation. Mit diesen Informationen können wir, wenn wir eine Zelle in der aktuellen Generation sehen, die Möglichkeiten der Nachbarschaft in der vorherigen Generation auf eine von vier bzw. eine von zwölf Möglichkeiten eingrenzen.Ich habe mich entschieden, die Nachbarschaft wie folgt darzustellen:
Dabei ist 0 das niedrigstwertige Bit und so weiter.
Die zweite Beobachtung ist, dass sich für zwei benachbarte Zellen in der aktuellen Generation die beiden Nachbarschaften der vorherigen Generation überlappen:
oder:
Im horizontalen Fall
2
überlappt sich die Nachbarschaft von links mit der Nachbarschaft3
von rechts und in ähnlicher Weise mit der0
von links und1
rechts. Im vertikalen Fall1
überlappt sich die Nachbarschaft von oben mit der Nachbarschaft3
von unten und in ähnlicher Weise mit der Nachbarschaft0
oben und2
unten.Diese Überlappung bedeutet, dass wir die Möglichkeiten für noch nicht ausgewählte Stadtteile basierend auf dem, was wir bereits ausgewählt haben, eingrenzen können. Der Code funktioniert von links nach rechts, von oben nach unten, in einer rekursiven Tiefensuche nach möglichen Vorbildern. Das folgende Diagramm zeigt, welche vorherigen Nachbarschaften wir berücksichtigen müssen, wenn wir die möglichen Nachbarschaften einer aktuellen Zelle betrachten:
Hier ist der Code:
Um es auszuführen:
quelle
O(<something>^n)
ich glaube.)