Un rompecabezas de la parte superior frontal es un rompecabezas en el que se requiere que construyas una forma tridimensional de bloques (generalmente cúbicos) con tres vistas ortogonales: una vista superior, una vista frontal y una vista lateral.
Por ejemplo, dada una vista superior, frontal y lateral de la siguiente manera:
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.
Un cubo de 2x2x2 (con volumen 8) satisfaría esta solución, pero es factible en el volumen 4, si tenemos la siguiente estructura de capas:
. . . . . . . .
. x . . . . x .
. . x . . x . .
. . . . . . . .
También hay algunos arreglos sin solución. Tomar como ejemplo:
Top: Front: Side:
. . . . . . . . . . . .
. . . . . . x . . . . .
. x . . . . . . . x . .
. . . . . . . . . . . .
Si la vista superior dice que el bloque es el segundo desde la izquierda, no hay forma de que coincida con la vista frontal que dice que el bloque debe ser el tercero desde la izquierda. Entonces este arreglo es imposible.
Su tarea es construir un programa que, dado un rompecabezas arbitrario de 4x4 en la parte superior frontal, intente resolverlo en la menor cantidad de cubos, o lo declare insoluble.
Su programa tomará como entrada una serie de 48 bits, que representan las vistas superior, frontal y lateral. Pueden estar en el formato que desee (una cadena de 6 bytes, una cadena de 0 y 1, un número hexadecimal de 12 dígitos, etc.), pero el orden de los bits debe mapearse como tal:
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
En otras palabras, los bits van en un orden de izquierda a derecha, de arriba a abajo, en la parte superior, luego frontal y luego lateral.
Luego, su programa generará una serie de 64 bits que indica los cubos en la cuadrícula de 4x4x4 que están rellenados, o indica que la cuadrícula no tiene solución.
Su programa se puntuará ejecutando una batería de 1,000,000 de casos de prueba.
Los datos de prueba se generarán tomando los hashes MD5 de los enteros "000000" a "999999" como cadenas, extrayendo los primeros 48 bits (12 hexits) de cada uno de estos hashes y usándolos como entrada para el frente superior rompecabezas lateral. A modo de ejemplo, estas son algunas de las entradas de prueba y los acertijos que generan:
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
Los dos primeros no tienen solución, mientras que el último tiene una solución con las siguientes capas, de adelante hacia atrás:
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.
La puntuación de su programa estará determinada por los siguientes criterios, en orden descendente de prioridad:
- El mayor número de casos resueltos.
- El menor número de bloques necesarios para resolver esos casos.
- El código más corto en bytes.
Debe enviar y calcular el puntaje usted mismo, lo que requiere que su programa pueda ejecutar todos los 1,000,000 de casos de prueba.
Respuestas:
Python: 5360 casos de prueba resueltos usando 69519 bloques, 594 bytes
Estos deberían ser los valores óptimos.
Acercarse:
Primero probaré si el caso de prueba tiene solución real. Hago esto inicializando una lista de longitud 64 por unidades y estableciendo todas las posiciones en cero, si el píxel correspondiente de las tres vistas es cero. Luego, veo el rompecabezas desde las 3 direcciones y miro si las vistas son las mismas que las vistas de entrada. Si son iguales, el rompecabezas es solucionable (ya encontramos la peor solución), de lo contrario no se puede resolver.
Luego hago un enfoque de bifurcación para encontrar la solución óptima.
Derivación: tengo una función recursiva. La profundidad de recursión indica cuántos valores ya están fijos. En cada llamada de la función me llamo dos veces, si el valor en el índice actual es 1 (este valor puede ser 0 o 1 en la solución óptima), o una vez, si el valor es 0 (tiene que ser cero en el solucion optima).
Límite: uso dos estrategias diferentes aquí.
Calculo las vistas desde los 3 lados en cada llamada de función y miro si aún coinciden con los valores de entrada. Si no coinciden, no llamo a la función de forma recursiva.
Mantengo la mejor solución en la memoria. Si ya hay más fijos en la rama actual que en la mejor solución, ya puedo cerrar esa rama. Además, puedo estimar un límite inferior para el número de bloques activados, que no son fijos. Y la condición se vuelve
#number of activated fixed blocks + #lower bound of activated blocks (under the not fixed blocks) < #number of activated blocks in the best solution.
Aquí está el código de Python. Define una función
f
que espera 3 listas que contienen 1s y 0s y devuelve 0 (no solucionable) o una lista de 1s y 0s que representa la solución óptima.La longitud del código es de 596 bytes / caracteres. Y aquí está el marco de prueba:
Puedes encontrar una versión no adaptada del programa aquí . También es un poco más rápido.
Resultados:
5360 de 1000000 rompecabezas son solucionables. En total necesitamos 69519 bloques. El número de bloques varía de 6 a 18 bloques. El rompecabezas más difícil tomó alrededor de 1 segundo para resolver. Es el rompecabezas con la semilla
"347177"
, que parecey tiene una solución óptima con 18 cubos. Los siguientes son algunos de arriba para cada una de las capas:
El tiempo total de ejecución para todos los casos de prueba fue de aproximadamente 90 segundos. Usé PyPy para ejecutar mi programa. CPython (el intérprete predeterminado de Python) es un poco más lento, pero también resuelve todos los acertijos en solo 7 minutos.
Puede encontrar el resultado completo aquí : el resultado se explica por sí mismo. Por ejemplo, el resultado del rompecabezas anterior es:
fuente
5360 casos resueltos con 69519 bloques; 923 bytes
Esto también es óptimo. Llame con una matriz de unos y ceros. Lanza un
NullPointerException
para entrada no válida. Se sacrifica algo de eficiencia para jugar golf. Todavía se completa dentro de un tiempo razonable para todas las 1000000 entradas de prueba.Estrategia:
En realidad, solía jugar a este rompecabezas bastante cuando tenía 10 años. Esto utiliza mi enfoque.
Paso 1:
Forme el cubo con la mayor cantidad de bloques que se ajuste a las vistas dadas.
Paso 2:
Crea una lista de piezas extraíbles. (Cualquier pieza con eso tiene otra pieza en la fila que está adentro, la columna está adentro y la viga está adentro).
Paso 3:
Pruebe todas las formas posibles de mantener o quitar cada pieza removible. (Vía fuerza bruta recursiva con poda).
Etapa 4:
Mantenga el mejor cubo válido.
Sin golf:
Programa completo:
fuente