Ein Top-Front-Side-Puzzle ist ein Puzzle, bei dem Sie eine 3D-Form von (normalerweise kubischen) Blöcken mit drei orthogonalen Ansichten konstruieren müssen: einer Draufsicht, einer Vorderansicht und einer Seitenansicht.
Beispiel für eine Draufsicht, eine Vorderansicht und eine Seitenansicht:
Top: Front: Side:
. . . . . . . . . . . .
. x x . . x x . . x x .
. x x . . x x . . x x .
. . . . . . . . . . . .
In this problem, the side view is taken from the right.
Ein 2x2x2 Würfel (mit Volumen 8) würde diese Lösung erfüllen, aber es ist in Volumen 4 machbar, wenn wir die folgende Schichtstruktur haben:
. . . . . . . .
. x . . . . x .
. . x . . x . .
. . . . . . . .
Es gibt auch einige unlösbare Vereinbarungen. Nehmen Sie zum Beispiel:
Top: Front: Side:
. . . . . . . . . . . .
. . . . . . x . . . . .
. x . . . . . . . x . .
. . . . . . . . . . . .
Wenn in der Draufsicht angegeben ist, dass der Block an zweiter Stelle von links liegt, kann die Vorderansicht nicht mit der Angabe übereinstimmen, dass der Block an dritter Stelle von links liegen muss. Diese Anordnung ist also unmöglich.
Ihre Aufgabe ist es, ein Programm zu erstellen, das bei einem beliebigen 4x4-Puzzle von oben nach vorne versucht, es in der geringsten Anzahl von Würfeln zu lösen, oder es für unlösbar erklärt.
Ihr Programm nimmt eine Reihe von 48 Bits als Eingabe, die die Draufsicht, die Vorderansicht und die Seitenansicht darstellen. Sie können in einem beliebigen Format vorliegen (eine 6-Byte-Zeichenfolge, eine Zeichenfolge aus 0en und 1en, eine 12-stellige Hex-Zahl usw.), die Reihenfolge der Bits muss jedoch wie folgt lauten:
Top: 0x00 Front: 0x10 Side: 0x20
0 1 2 3 0 1 2 3 0 1 2 3
4 5 6 7 4 5 6 7 4 5 6 7
8 9 a b 8 9 a b 8 9 a b
c d e f c d e f c d e f
Mit anderen Worten, die Bits werden von links nach rechts, von oben nach unten, von oben nach vorne und dann von der Seite betrachtet.
Ihr Programm gibt dann entweder eine Reihe von 64 Bit aus, die die ausgefüllten Würfel im 4x4x4-Raster anzeigen, oder Sie geben an, dass das Raster nicht lösbar ist.
Ihr Programm wird mit einer Batterie von 1.000.000 Testfällen bewertet.
Die Testdaten werden generiert, indem die MD5-Hashes der Ganzzahlen "000000" bis "999999" als Zeichenfolgen verwendet werden, die ersten 48 Bits (12 Hexits) jeder dieser Hashes extrahiert werden und als Eingabe für die Top-Front-Front-Funktion verwendet werden. Seitenrätsel. Als Beispiel hier sind einige der Testeingaben und die Rätsel, die sie erzeugen:
Puzzle seed: 000000 hash: 670b14728ad9
Top: Front: Side:
. x x . . . . x x . . .
x x x x . x . x x . x .
. . . . . x x x x x . x
x . x x . . x . x . . x
Puzzle seed: 000001 hash: 04fc711301f3
Top: Front: Side:
. . . . . x x x . . . .
. x . . . . . x . . . x
x x x x . . . x x x x x
x x . . . . x x . . x x
Puzzle seed: 000157 hash: fe88e8f9b499
Top: Front: Side:
x x x x x x x . x . x x
x x x . x . . . . x . .
x . . . x x x x x . . x
x . . . x . . x x . . x
Die ersten beiden sind unlösbar, während die letzte Lösung von vorne nach hinten die folgenden Ebenen enthält:
x . . . . . . . x x x . x x x .
. . . . x . . . . . . . . . . .
x . . . . . . . . . . . x x x x
x . . . . . . . . . . . x . . x
There are a total of 16 blocks here, but it can probably be done in less.
Die Punktzahl Ihres Programms wird anhand der folgenden Kriterien in absteigender Reihenfolge der Priorität bestimmt:
- Die höchste Anzahl gelöster Fälle.
- Die niedrigste Anzahl von Blöcken, die zur Lösung dieser Fälle erforderlich sind.
- Der kürzeste Code in Bytes.
Sie müssen die Punktzahl selbst einreichen und berechnen. Dies setzt voraus, dass Ihr Programm alle 1.000.000 Testfälle durchlaufen kann.
Antworten:
Python: 5360 Testfälle mit 69519 Blöcken, 594 Bytes gelöst
Dies sollten die optimalen Werte sein.
Ansatz:
Zuerst werde ich testen, ob der Testfall tatsächlich lösbar ist. Dazu initialisiere ich eine Liste der Länge 64 nach Einsen und setze alle Positionen auf Null, wenn dort das entsprechende Pixel der drei Ansichten Null ist. Dann betrachte ich das Puzzle einfach aus allen drei Richtungen und überprüfe, ob die Ansichten mit den Eingabeansichten übereinstimmen. Wenn es gleich ist, ist das Rätsel lösbar (wir haben bereits die schlechteste Lösung gefunden), andernfalls ist es nicht lösbar.
Dann mache ich einen branch-and-bound Ansatz, um die optimale Lösung zu finden.
Verzweigung: Ich habe eine rekursive Funktion. Die Rekursionstiefe gibt an, wie viele Werte bereits festgelegt sind. Bei jedem Aufruf der Funktion rufe ich sich zweimal auf, wenn der Wert am aktuellen Index 1 ist (dieser Wert kann in der optimalen Lösung 0 oder 1 sein), oder einmal, wenn der Wert 0 ist (er muss in der Funktion Null sein) optimale Lösung).
Bounding: Ich benutze hier zwei verschiedene Strategien.
Ich berechne die Ansichten von den 3 Seiten in jedem Funktionsaufruf und schaue, ob sie noch mit den Eingabewerten übereinstimmen. Wenn sie nicht übereinstimmen, rufe ich die Funktion nicht rekursiv auf.
Ich behalte die beste Lösung im Gedächtnis. Wenn es in der aktuellen Filiale bereits mehr feste gibt als in der besten Lösung, kann ich diese Filiale bereits schließen. Zusätzlich kann ich eine Untergrenze für die Anzahl der aktivierten Blöcke schätzen, die nicht festgelegt sind. Und der Zustand wird
#number of activated fixed blocks + #lower bound of activated blocks (under the not fixed blocks) < #number of activated blocks in the best solution.
Hier ist der Python-Code. Es definiert eine Funktion,
f
die 3 Listen mit 1 und 0 erwartet und entweder 0 (nicht lösbar) oder eine Liste mit 1 und 0 zurückgibt, die die optimale Lösung darstellt.Die Codelänge beträgt 596 Bytes / Zeichen. Und hier ist das Test-Framework:
Sie können eine ungolfed Version des Programms finden hier . Es ist auch ein bisschen schneller.
Ergebnisse:
5360 von 1000000 Puzzles sind lösbar. Insgesamt benötigen wir 69519 Blöcke. Die Anzahl der Blöcke variiert zwischen 6 und 18 Blöcken. Die Lösung des schwierigsten Rätsels dauerte ungefähr 1 Sekunde. Es ist das Puzzle mit dem Samen
"347177"
, wie es aussiehtund hat mit 18 würfel eine optimale lösung. Das Folgende ist ein paar von oben für jede der Schichten:
Die Gesamtlaufzeit für alle Testfälle betrug ca. 90 Sekunden. Ich habe PyPy benutzt, um mein Programm auszuführen. CPython (der Standard-Python-Interpreter) ist etwas langsamer, löst aber auch alle Rätsel in nur 7 Minuten.
Die vollständige Ausgabe finden Sie hier : Die Ausgabe ist selbsterklärend. ZB ist die Ausgabe für das obige Puzzle:
quelle
5360 Fälle mit 69519 Blöcken gelöst; 923 Bytes
Das ist auch optimal. Rufen Sie mit einer Reihe von Einsen und Nullen auf. Löst ein
NullPointerException
für ungültige Eingaben aus. Ein gewisser Wirkungsgrad wird geopfert, um Golf zu spielen. Es ist immer noch innerhalb einer angemessenen Zeit für alle 1000000 Testeingaben abgeschlossen.Strategie:
Eigentlich habe ich dieses Puzzle ziemlich oft gespielt, als ich 10 Jahre alt war. Dies verwendet meinen Ansatz.
Schritt 1:
Bilden Sie den Würfel mit den meisten Blöcken, die den angegebenen Ansichten entsprechen.
Schritt 2:
Erstellen Sie eine Liste mit entfernbaren Teilen. (Jedes Stück mit diesem hat ein anderes Stück in der Reihe, in der Spalte und im Balken.)
Schritt 3:
Testen Sie alle Möglichkeiten, um jedes herausnehmbare Teil aufzubewahren oder zu entfernen. (Über rekursive Brute-Force mit Beschneiden.)
Schritt 4:
Behalte den besten gültigen Würfel.
Ungolfed:
Volles Programm:
quelle