Układanka z przodu z przodu to układanka, w której musisz zbudować trójwymiarowy (zwykle sześcienny) blok z trzema prostopadłymi widokami: widokiem z góry, widokiem z przodu i widokiem z boku.
Na przykład, biorąc pod uwagę widok z góry, z przodu i z boku w następujący sposób:
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.
Kostka 2x2x2 (z tomem 8) spełniałaby to rozwiązanie, ale jest wykonalna w tomie 4, jeśli mamy następującą strukturę warstw:
. . . . . . . .
. x . . . . x .
. . x . . x . .
. . . . . . . .
Istnieją również pewne nierozwiązywalne ustalenia. Weź na przykład:
Top: Front: Side:
. . . . . . . . . . . .
. . . . . . x . . . . .
. x . . . . . . . x . .
. . . . . . . . . . . .
Jeśli widok z góry mówi, że blok jest drugi od lewej, nie ma sposobu, aby dopasować się do widoku z przodu, który mówi, że blok musi być trzeci od lewej. Więc to ustawienie jest niemożliwe.
Twoim zadaniem jest zbudowanie programu, który, biorąc pod uwagę dowolną układankę 4x4 od góry, próbuje rozwiązać go w jak najmniejszej liczbie kostek lub ogłasza, że jest nierozwiązywalny.
Twój program pobierze jako ciąg 48 bitów reprezentujących widoki z góry, z przodu i z boku. Mogą być w dowolnym formacie (ciąg 6-bajtowy, ciąg zer i jedynek, 12-cyfrowy numer szesnastkowy itp.), Ale kolejność bitów musi być odwzorowana jako taka:
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
Innymi słowy, bity są ułożone od lewej do prawej, od góry do dołu, w widoku od góry, od przodu, a następnie z boku.
Twój program wyświetli wtedy albo serię 64 bitów, wskazując wypełnione kostki w siatce 4x4x4, albo wskaże, że siatka jest nierozwiązywalna.
Twój program zostanie oceniony przez uruchomienie baterii 1 000 000 przypadków testowych.
Dane testowe zostaną wygenerowane przez wzięcie skrótów MD5 liczb całkowitych od „000000” do „999999” jako ciągów, wyodrębnienie pierwszych 48 bitów (12 heksów) każdego z tych skrótów i wykorzystanie ich jako danych wejściowych dla górnego-przedniego- układanka boczna. Oto przykładowe dane wejściowe testowe i generowane przez nich zagadki:
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
Pierwsze dwa są nierozwiązywalne, podczas gdy ostatni ma rozwiązanie z następującymi warstwami, od przodu do tyłu:
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.
Wynik Twojego programu zostanie określony na podstawie następujących kryteriów, w malejącej kolejności priorytetów:
- Największa liczba rozwiązanych przypadków.
- Najmniejsza liczba bloków wymagana do rozwiązania tych przypadków.
- Najkrótszy kod w bajtach.
Musisz przesłać i obliczyć wynik samodzielnie, co wymaga, aby Twój program mógł przejść przez wszystkie 1 000 000 przypadków testowych.
Odpowiedzi:
Python: 5360 przypadków testowych rozwiązanych przy użyciu bloków 69519, 594 bajtów
To powinny być wartości optymalne.
Podejście:
Najpierw przetestuję, czy przypadek testowy można rozwiązać. Robię to, inicjując listę długości 64 według nich i ustawiając wszystkie pozycje na zero, jeśli tam piksel trzech widoków wynosi zero. Następnie patrzę prosto na puzzle ze wszystkich 3 kierunków i sprawdzam, czy widoki są takie same jak widoki wejściowe. Jeśli są równe, łamigłówka jest do rozwiązania (znaleźliśmy już najgorsze rozwiązanie), w przeciwnym razie jest nierozwiązywalna.
Następnie stosuję podejście odgałęzione w celu znalezienia optymalnego rozwiązania.
Rozgałęzienie: Mam funkcję rekurencyjną. Głębokość rekurencji informuje, ile wartości jest już ustalonych. W każdym wywołaniu funkcji wywołuję się dwa razy, jeśli wartość przy bieżącym indeksie wynosi 1 (wartość ta może wynosić 0 lub 1 w optymalnym rozwiązaniu), lub jeden raz, jeśli wartość wynosi 0 (musi być zero w optymalne rozwiązanie).
Ograniczanie: używam tutaj dwóch różnych strategii.
Obliczam widoki z 3 stron w każdym wywołaniu funkcji i sprawdzam, czy nadal odpowiadają one wartościom wejściowym. Jeśli się nie zgadzają, nie wywołuję funkcji rekurencyjnie.
Najlepsze rozwiązanie przechowuję w pamięci. Tam jest już więcej stałych w bieżącej gałęzi niż w najlepszym rozwiązaniu, mogę już zamknąć tę gałąź. Dodatkowo mogę oszacować dolną granicę liczby aktywowanych bloków, które nie są stałe. I stan się staje
#number of activated fixed blocks + #lower bound of activated blocks (under the not fixed blocks) < #number of activated blocks in the best solution.
Oto kod Python. Definiuje funkcję,
f
która oczekuje 3 list zawierających 1s i 0s i zwraca 0 (nierozwiązywalne) lub listę 1 i 0 reprezentujących optymalne rozwiązanie.Długość kodu wynosi 596 bajtów / znaków. A oto ramy testowe:
Możesz znaleźć wersję programu bez golfa tutaj . Jest także trochę szybszy.
Wyniki:
5360 ze 1000000 łamigłówek jest do rozwiązania. W sumie potrzebujemy 69519 bloków. Liczba bloków waha się od 6 do 18 bloków. Rozwiązanie najtrudniejszej układanki zajęło około 1 sekundy. To układanka z ziarnem
"347177"
, które wyglądai ma optymalne rozwiązanie z 18 kostkami. Oto kilka z góry dla każdej z warstw:
Całkowity czas działania wszystkich przypadków testowych wyniósł około 90 sekund. Użyłem PyPy do uruchomienia mojego programu. CPython (domyślny interpreter języka Python) jest nieco wolniejszy, ale rozwiązuje wszystkie zagadki w zaledwie 7 minut.
Możesz znaleźć pełny wynik tutaj : wynik jest oczywisty. Np. Wynik dla powyższej układanki to:
źródło
5360 spraw rozwiązanych za pomocą 69519 bloków; 923 bajty
Jest to również optymalne. Zadzwoń z tablicą zer i jedynek. Zgłasza a
NullPointerException
dla niepoprawnego wejścia. Pewna wydajność poświęcana jest na golfa. Nadal kończy się w rozsądnym czasie dla wszystkich 1000000 wejść testowych.Strategia:
Kiedy miałem 10 lat, grałem w tę zagadkę dość często. To moje podejście.
Krok 1:
Utwórz sześcian z największą liczbą bloków pasujących do podanych widoków.
Krok 2:
Utwórz listę elementów wymiennych. (Każdy element z tym ma inny element w rzędzie jest w środku, kolumna jest w środku, a belka jest w środku.)
Krok 3:
Przetestuj każdy możliwy sposób, aby zachować lub usunąć każdy wyjmowany element. (Poprzez rekurencyjną brutalną siłę z przycinaniem.)
Krok 4:
Zachowaj najlepszą prawidłową kostkę.
Nie golfowany:
Pełny program:
źródło