Tarea
Escriba un programa que lea tres enteros m , n desde STDIN o como argumentos de línea de comandos, imprima todas las posibles inclinaciones de un rectángulo de dimensiones m × n por dominó 2 × 1 y 1 × 2 y finalmente el número de inclinaciones válidas.
Las fichas de dominó de un mosaico individual se deben representar con dos guiones ( -
) para 2 × 1 y dos barras verticales ( |
) para fichas de 1 × 2 . Cada mosaico (incluido el último) debe ir seguido de un salto de línea.
Para fines de puntuación, también debe aceptar un indicador de STDIN o como argumento de línea de comando que haga que su programa imprima solo el número de inclinaciones válidas, pero no las inclinaciones en sí.
Su programa no puede tener más de 1024 bytes. Tiene que funcionar para todas las entradas de modo que m × n ≤ 64 .
(Inspirado en Imprimir todas las inclinaciones de dominó del rectángulo 4x6 ).
Ejemplo
$ sdt 4 2
----
----
||--
||--
|--|
|--|
--||
--||
||||
||||
5
$ sdt 4 2 scoring
5
Puntuación
Su puntaje está determinado por el tiempo de ejecución de su programa para la entrada 8 8 con el indicador establecido.
Para hacer de este un código más rápido en lugar de un desafío informático más rápido , ejecutaré todas las presentaciones en mi propia computadora (Intel Core i7-3770, 16 GiB PC3-12800 RAM) para determinar el puntaje oficial.
Deje instrucciones detalladas sobre cómo compilar y / o ejecutar su código. Si necesita una versión específica del compilador / intérprete de su idioma, haga una declaración al respecto.
Me reservo el derecho de dejar las presentaciones sin puntaje si:
No hay un compilador / intérprete gratuito (como en cerveza) para mi sistema operativo (Fedora 21, 64 bits).
A pesar de nuestros esfuerzos, su código no funciona y / o produce resultados incorrectos en mi computadora.
La compilación o ejecución lleva más de una hora.
Su código o el único compilador / intérprete disponible contiene una llamada al sistema
rm -rf ~
o algo igualmente sospechoso.
Tabla de clasificación
He vuelto a calificar todas las presentaciones, ejecutando compilaciones y ejecuciones en un bucle con 10,000 iteraciones para la compilación y entre 100 y 10,000 iteraciones para la ejecución (dependiendo de la velocidad del código) y calculando la media.
Estos fueron los resultados:
User Compiler Score Approach
jimmy23013 GCC (-O0) 46.11 ms = 1.46 ms + 44.65 ms O(m*n*2^n) algorithm.
steveverrill GCC (-O0) 51.76 ms = 5.09 ms + 46.67 ms Enumeration over 8 x 4.
jimmy23013 GCC (-O1) 208.99 ms = 150.18 ms + 58.81 ms Enumeration over 8 x 8.
Reto Koradi GCC (-O2) 271.38 ms = 214.85 ms + 56.53 ms Enumeration over 8 x 8.
fuente
--
. Si es vertical, son dos|
, uno debajo del otro.Respuestas:
C
Una implementación sencilla ...
La versión trampa
Explicación del algoritmo más rápido.
Escanea de izquierda a derecha y mantiene el estado
d[i][j]
, donde:i
está en[0,m)
, lo que significa la columna actual.j
es un vector de tamaño de bitn
, donde el bit sería 1 si la posición correspondiente en la columnai
ya está ocupada antes de comenzar a trabajar en esta columna. Es decir, está ocupado por la mitad derecha de a--
.d[i][j]
es el número total de diferentes inclinaciones.Luego diga
e[i][j]
= la suma ded[i][k]
dónde puede colocar la base de dominó verticalk
para formar aj
.e[i][j]
sería el número de inclinaciones donde cada 1 bitj
está ocupado por cualquier cosa que no sea la mitad izquierda de a--
. Llénalos--
y obtendrásd[i+1][~j]
=e[i][j]
.e[m-1][every bit being 1]
od[m][0]
es la respuesta final.Una implementación ingenua le dará la complejidad del tiempo en algún lugar cercano
g[n]=2*g[n-1]+g[n-2] = O((sqrt(2)+1)^n)
(ya lo suficientemente rápido si n = m = 8). Pero en su lugar, puede hacer un bucle en primer lugar para cada dominó posible, e intentar agregarlo a cada mosaico que pueda tener este dominó agregado, y fusionar el resultado con la matriz originald
(como el algoritmo para el problema Mochila). Y esto se convierte en O (n * 2 ^ n). Y todo lo demás son detalles de implementación. Todo el código se ejecuta en O (m * n * 2 ^ n).fuente
-O1
parece ser el punto óptimo. He probado todos los niveles de optimización.)C
Después de una ronda de optimizaciones, y adaptadas para las reglas modificadas:
Comencé a toparme con el límite de longitud de 1024 caracteres, así que tuve que reducir un poco la legibilidad. Nombres de variables mucho más cortos, etc.
Instrucciones de construcción:
Ejecutar con salida de solución habilitada:
Ejecutar con solo recuento de soluciones:
Algunos comentarios:
-O2
parece ser bueno.También tenga en cuenta que el código aún genera las soluciones reales, incluso en el modo "contar solo". Cada vez que se encuentra una solución, la
vM
máscara de bits contiene una1
para las posiciones que tienen una barra vertical y una0
para las posiciones con una barra horizontal. Solo se omite la conversión de esta máscara de bits en formato ASCII y la salida real.fuente
-O2
debería ser bueno.-O2
parece ser el punto óptimo. He probado todos los niveles de optimización.)C
El concepto es encontrar primero todos los arreglos posibles de dominó horizontal en una fila, almacenarlos
r[]
y luego organizarlos para dar todos los arreglos posibles de dominó vertical.El código para colocar las fichas de dominó horizontales en una fila se modifica a partir de esta respuesta mía: https://codegolf.stackexchange.com/a/37888/15599 . Es lento para las cuadrículas más anchas, pero eso no es un problema para el caso de 8x8.
La innovación está en la forma en que se ensamblan las filas. Si el tablero tiene un número impar de filas, se gira 90 grados en el análisis de entrada, por lo que ahora tiene un número par de filas. Ahora coloco algunas fichas de dominó verticales en la línea central. Debido a la simetría, si hay
c
formas de organizar las fichas de dominó restantes en la mitad inferior, también debe haberc
formas de organizar las fichas de dominó restantes en la mitad superior, lo que significa que para una disposición dada de fichas de dominó verticales en la línea central, hayc*c
posibles soluciones. . Por lo tanto, solo se analiza la línea central más la mitad del tablero cuando se requiere que el programa imprima solo el número de soluciones.f()
construye la tabla de posibles arreglos de fichas de dominó horizontales y explora las posibles disposiciones de fichas de dominó verticales en la línea central. luego llama a la función recursivag()
que llena las filas. Si se requiere imprimir,h()
se llama a la función para hacer esto.g()
Se llama con 3 parámetros.y
es la fila actual yd
es la dirección (arriba o abajo) en la que estamos llenando el tablero desde el centro hacia afuera.x
contiene un mapa de bits que indica las fichas de dominó verticales que están incompletas de la fila anterior. Se intentan todos los arreglos posibles de dominó en una fila desde r []. En esta matriz, un 1 representa un dominó vertical y un par de ceros un dominó horizontal. Una entrada válida en la matriz debe tener por lo menos lo suficiente como para terminar 1 de los dominós verticales incompletas desde la última fila:(x&r[j])==x
. Puede tener más 1, lo que indica que se están comenzando nuevas fichas de dominó verticales. Para la siguiente fila, entonces, solo necesitamos las nuevas fichas de dominó, así que llamamos al procedimiento nuevamente conx^r[j]
.Si se ha alcanzado una fila final y no hay dominó vertical incompleto colgando de la parte superior o inferior del tablero,
x^r[j]==0
entonces la mitad se ha completado con éxito. Si no estamos imprimiendo, es suficiente completar la mitad inferior y usarc*c
para calcular el número total de arreglos. Si estamos imprimiendo, será necesario completar también la mitad superior y luego llamar a la función de impresiónh()
.CÓDIGO
Tenga en cuenta que la entrada con un número impar de filas y un número par de columnas se gira 90 grados en la fase de análisis. Si esto es inaceptable, la función de impresión
h()
se puede cambiar para acomodarlo. (EDITAR: no es obligatorio, ver comentarios).EDITAR: Se
e()
ha utilizado una nueva función para verificar la paridad dei
(es decir, el número de fichas de dominó que se ubican en la línea central). La paridad dei
(la cantidad de medias fichas de dominó en la línea central que sobresale en cada mitad del tablero) debe ser la misma que la rareza del número total de espacios en cada mitad (dado porn/2
) porque solo entonces las fichas de dominó pueden llenar todo el espacio disponible. Esta edición elimina la mitad de los valores de i y, por lo tanto, hace que mi programa sea aproximadamente el doble de rápido.fuente
-O0
fue el punto dulce para el total Otras opciones de compilación se desaceleró..)32 2 s
. Lo detuve después de unos 15 minutos.2 32 s
ejecuta casi al instante. El escaneo a través de todos los dominós verticales posibles es extremadamente inútil para elH=2
caso, porque de hecho ya tenemos toda la información necesariar[]
. Estoy muy satisfecho con la hora oficial de8 8 s
Aquí hay un parche para el caso que mencionas:if(H==2){C=p;if(!S)for(i=0;i<p;i++)q[0]=q[1]=r[i],h();}else for(i=0;i<=k;i++)c=0,g(H/2,1,i),C+=c*c;
como puedes ver, este fragmento se ejecutará instantáneamenteH=2
con el conjunto de banderas. El tiempo de ejecución general está limitado por el edificio,r[]
que ciertamente tiene margen de mejora.if(t)for(a=n;a--;a%H||puts(""))putchar(124-(q[a%H]>>a/H)%2*79);else for(a=n;a--;a%W||puts(""))putchar(45+(q[a/W]>>a%W)%2*79);
longitud de código todavía está muy por debajo de 1000 bytes y el impacto en el tiempo de compilación debería ser mínimo. No incluí estos parches anoche porque estaba demasiado cansado.