Número de inclinaciones de dominó

9

Escribir un programa o función que dado positivo n y m calcula el número de mosaicos dominó distintas válidas que puede caber en un n por m rectángulo. Esta es la secuencia A099390 en la Enciclopedia en línea de secuencias enteras . Puede tomar la entrada como argumento (s) de función, CLA o en stdin, en cualquier formato razonable. Debe devolver o imprimir un entero entero como salida.

Cada mosaico no debe dejar espacios, y se cuenta cada mosaico distinto, incluidas las rotaciones, reflexiones, etc. Por ejemplo, las inclinaciones para 2x3 son:

|--    |||    --| 
|--    |||    --|

Ejemplo de entradas / salidas:

1,  9 -> 0
2,  2 -> 2
2,  3 -> 3
4,  4 -> 36
4,  6 -> 281
6,  6 -> 6728
7, 10 -> 53175517

Su programa debe trabajar en teoría, para cualquier n y m , pero si su programa requiere demasiada memoria o el tipo de datos se desborda excusado. Sin embargo, su programa debe funcionar correctamente para cualquier n, m <= 8.


El código más corto en bytes gana.

orlp
fuente
Podrías habernos hecho la vida mucho más fácil si solo hubieras permitido áreas de 2n x 2m , ¡buen desafío!
flawr
Al igual que esta pregunta codegolf.stackexchange.com/q/51067/15599 solo más corta y más lenta
Level River St
@ edc65 Damnit = / Parece que no puedo pensar en nada nuevo ... Casi todos los desafíos en los que pienso ya se han hecho de alguna forma. De cualquier manera, los desafíos no son exactamente los mismos, ya que mi pregunta es un código de golf, y no tiene que encontrar las inclinaciones, solo la cantidad de ellas. Tal vez la gente pueda usar buenas fórmulas en lugar de escribir un bruteforcer.
orlp
De acuerdo - va a eliminar el otro comentario
edc65
Comentario copiado de bilbo (que publicó como respuesta debido a 1 repetición): "Este problema es un desafío de SPOJ acortado : spoj.com/problems/MNTILE El código más corto en SPOJ es de 98 bytes en awk". . Parece que soy doblemente original, no estaba al tanto.
orlp

Respuestas:

3

Pyth, 30 29 bytes

L?bsmy-tb]dfq1.a-VThbb1y*FUMQ

Pruébelo en línea: Demonstration / Test Suite

Todas las entradas de ejemplo se ejecutan en el compilador en línea. Sin embargo, el último tarda unos segundos.

Explicación:

En mi código definiré una función recursiva y. La función ytoma una lista de coordenadas 2D y devuelve el número de diferentes inclinaciones de dominó utilizando estas coordenadas. Por ejemplo y([[0,0], [0,1]]) = 1(un dominó horizontal), y([[0,0], [1,1]]) = 0(las coordenadas no son adyacentes) y y([[0,0], [0,1], [1,0], [1,1]]) = 2(dos dominós horizontales o dos verticales). Después de definir la función, la llamaré con todas las coordenadas [x,y]con x in [0, 1, m-1], y in [0, 1, n-1].

¿Cómo funciona la función recursiva? Es bastante simple. Si la lista de coordenadas está vacía, hay exactamente un mosaico válido y yretornos 1.

De lo contrario, tomo la primera coordenada de la lista b[0]y busco las coordenadas restantes para un vecino. Si no hay ningún vecino b[0], entonces no es posible el mosaico, por lo tanto, devuelvo 0. Si hay uno o más vecinos, entonces el número de inclinaciones es (el número de inclinaciones donde me conecto b[0]con el primer vecino a través de una domina, más el número de inclinaciones donde me conecto b[0]con el segundo vecino, más ...) Entonces llamo a la función de forma recursiva para cada vecino con la lista acortada (eliminando las dos coordenadas b[0]y el vecino). Después, resumo todos los resultados y los devuelvo.

Debido al orden de los cables, siempre hay dos vecinos posibles, el del lado derecho y el de abajo. Pero mi algoritmo no se preocupa por eso.

                          UMQ  convert the input numbers into ranges
                        *F     Cartesian product (coords of each square)
L                              define a function y(b):
 ?b                              if len(b) > 0:
           f         b             filter b for squares T, which satisfy:
              .a-VThb                Euclidean distance between T and b[0]
            q1                       is equal to 1 (direct neighbors)
    m                              map each neighbor d to:
      -tb]d                          remove d from b[1]
     y                               and call recursively y with the rest
   s                               sum all those values and return them
                                 else:
                      1            return 1 (valid domino tiling found)
                       y*FUMQ  Call y with all coords and print the result  
Jakube
fuente
¿Puede contarnos un poco más sobre cómo funciona su programa? No pude descifrar su algoritmo a partir de los comentarios.
error
@flawr Agregué una explicación de mi algoritmo.
Jakube
@Jaketube Gracias por la explicación, ¡realmente me gusta el enfoque recursivo!
error
3

Matlab, 292

Estoy seguro de que esto se puede acortar mucho simplemente portándolo a otro idioma.

La idea básica es la fuerza bruta: se me ocurrió una especie de enumeración de todas las formas de colocar m*n/2ladrillos de dominó en un m*ntablero. Pero esta enumeración también incluye muchas inclinaciones no válidas (ladrillos que se superponen o salen del tablero). Por lo tanto, el programa construye todas esas inclinaciones y solo cuenta las válidas. Se trata de la complejidad del tiempo de ejecución O(2^(m*n/2) * m*n). La memoria no es un problema 8x8ya que solo necesita O(m*n)memoria. Pero el tiempo necesario 8x8es de unos 20 días.

Aquí la versión completamente comentada que explica lo que está sucediendo.

PD: Si alguien sabe cómo hacer que el resaltado de sintaxis de Matlab funcione, ¡incluya la etiqueta correspondiente en esta respuesta!

function C=f(m,n)
d = ceil(m*n/2);%number of dominoes
%enumeration: %the nth bit in the enumeration says whether the nth 
% domino pice is upright or not. we enumerate like this:
% firt piece goes top left:
% next piece goes to the left most column that has an empty spot, in the
% top most empty spot of that column
C=0;%counter of all valid tilings
for e=0:2^d-1 %go throu all enumerations
    %check whether each enumeration is valid
    A = ones(m,n);
    %empty spots are filled with 1
    %filled spots are 0 (or if overlapping <0) 
    v=1;%flag for the validity. hte grid is assumed to be valid until proven otherwise
    for i=1:d %go throu all pieces, place them in A
        %find the column where to place:
        c=find(sum(A)>0,1);
        %find the row where to place:
        r=find(A(:,c)>0,1);
        %find direction of piece:
        b=de2bi(e,d);
        if b(i)
            x=0;y=1;
        else
            x=1;y=0;
        end
        %fill in the piece:
        try
            A(r:r+y,c:c+x)=A(r:r+y,c:c+x)-1;
        catch z
            v=0;break;
        end
        %check whether A has no overlapping pieces
        if any(A(:)<0)
            v=0;break;
        end
    end
    %if valid, count it as valid
    if v && ~norm(A(:))
        disp(A)
        C=C+1;
    end
end

Aquí el totalmente golfizado:

function C=f(m,n);m=4;n=6;d=ceil(m*n/2);C=0;for e=0:2^d-1;A=ones(m,n);v=1;for i=1:d;c=find(sum(A)>0,1);r=find(A(:,c)>0,1);b=de2bi(e,d);if b(i);x=0;y=1;else;x=1;y=0;end;try;A(r:r+y,c:c+x)=A(r:r+y,c:c+x)-1;catch z;v=0;break;end;if any(A(:)<0);v=0;break;end;end;if v && ~norm(A(:));C=C+1;end;end
falla
fuente
2

C89, 230 bytes

f(n,m,b)int*b;{int s,i;s=i=0;
while(b[i])if(++i==n*m)return 1;
if(i/n<m-1){b[i]=b[i+n]=1;s+=f(n,m,b);b[i]=b[i+n]=0;}
if(i%n<n-1&&!(b[i]|b[i+1])){b[i]=b[i+1]=1;s+=f(n,m,b);b[i]=b[i+1]=0;}
return s;}
g(n,m){int b[99]={};return f(n,m,b);}

Para facilitar la lectura, escribí esta respuesta a mano: todas las líneas nuevas se pueden eliminar de forma segura para llegar a 230 bytes.

Define una función int g(int n, int m)que devuelve el número de inclinaciones. Utiliza una función auxiliar fque itera sobre todas las inclinaciones válidas colocando un dominó, recurriendo y luego eliminando el dominó en un tablero compartido.

orlp
fuente
0

Python 243

Opté por un enfoque de fuerza bruta:

  • generar m * n / 2 direcciones;
  • intente colocar el dominó en el tablero m * n.

Si todos encajan y no quedan espacios, tenemos una entrada válida.

Aquí está el código:

import itertools as t
m,n=input()
c,u=0,m*n
for a in t.product([0,1],repeat=u/2):
 l,k,r,h=[' ',]*u,0,'-|',[1,m]
 for t in a:
  l[k]=r[t]
  k+=h[t]   
  if k%m<m and k/m<n and l[k]==' ':l[k]=r[t]
  k=''.join(l).find(' ',1)
 if k<0:c+=1
print c
Willem
fuente