Nombre de carrelages domino

9

Écrivez un programme ou une fonction qui, étant donné n et m positifs , calcule le nombre de pavages domino distincts valides que vous pouvez insérer dans un rectangle n par m . Il s'agit de la séquence A099390 dans l' Encyclopédie en ligne des séquences de nombres entiers . Vous pouvez prendre les entrées en tant qu'argument (s) de fonction, CLA ou sur stdin, dans n'importe quel format raisonnable. Vous devez renvoyer ou imprimer un seul entier en sortie.

Chaque pavage ne doit laisser aucun espace et chaque pavage distinct est compté, y compris les rotations, les réflexions, etc. Par exemple, les pavages pour 2x3 sont:

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

Exemples d'entrées / sorties:

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

Votre programme devrait théoriquement fonctionner pour n et m , mais si votre programme nécessite trop de mémoire ou si votre type de données déborde, il est excusé. Cependant, votre programme doit fonctionner correctement pour tout n, m <= 8.


Le code le plus court en octets gagne.

orlp
la source
Vous auriez pu nous faciliter la vie si vous n'aviez autorisé que des zones de 2n x 2m , beau défi!
2015
Tout comme cette question codegolf.stackexchange.com/q/51067/15599 seulement plus court et plus lent
Level River St
@ edc65 Damnit = / Je n'arrive pas à penser à quelque chose de nouveau ... Presque chaque défi auquel je pense a déjà été fait sous une forme ou une autre. Quoi qu'il en soit, les défis ne sont pas exactement les mêmes puisque ma question est un golf de code, et vous n'avez pas à trouver les pavages - seulement le montant d'entre eux. Peut-être que les gens peuvent utiliser de belles formules au lieu d'écrire un bruteforcer.
orlp
D'accord - va supprimer l'autre commentaire
edc65
Commentaire de Bilbo copié (qu'il a publié comme réponse en raison de 1 répétition): "Ce problème est un défi SPOJ raccourci: spoj.com/problems/MNTILE Le code le plus court sur SPOJ est de 98 octets en awk." . On dirait que je suis doublement non original - je n'étais pas au courant.
orlp

Réponses:

3

Pyth, 30 29 octets

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

Essayez-le en ligne: Demonstration / Test Suite

Tous les exemples d'entrées s'exécutent dans le compilateur en ligne. Le dernier prend cependant quelques secondes.

Explication:

Dans mon code, je définirai une fonction récursive y. La fonction yprend une liste de coordonnées 2D et renvoie le nombre de pavages de dominos différents en utilisant ces coordonnées. Par exemple y([[0,0], [0,1]]) = 1(un domino horizontal), y([[0,0], [1,1]]) = 0(les coordonnées ne sont pas adjacentes) et y([[0,0], [0,1], [1,0], [1,1]]) = 2(soit deux dominos horizontaux soit deux dominos verticaux). Après avoir défini la fonction, je l'appellerai avec toutes les coordonnées [x,y]avec x in [0, 1, m-1], y in [0, 1, n-1].

Comment fonctionne la fonction récursive? C'est assez simple. Si la liste des accords est vide, il y a exactement un pavage valide et yretourne 1.

Sinon, je prends la première coordonnée de la liste b[0]et recherche les coordonnées restantes pour un voisin. S'il n'y a pas de voisin b[0], alors il n'y a pas de mosaïque possible, donc je retourne 0. S'il y a un ou plusieurs voisins, alors le nombre de mosaïques est (le nombre de mosaïques où je me connecte b[0]avec le premier voisin via une domina, plus le nombre de pavages où je me connecte b[0]avec le deuxième voisin, plus ...) J'appelle donc la fonction récursivement pour chaque voisin avec la liste raccourcie (en supprimant les deux coords b[0]et le voisin). Ensuite, je résume tous les résultats et les renvoie.

En raison de l'ordre des coordonnées, il n'y a toujours que deux voisins possibles, celui de droite et celui du dessous. Mais mon algorithme ne s'en soucie pas.

                          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
la source
Pouvez-vous nous en dire un peu plus sur le fonctionnement de votre programme? Je n'ai pas pu comprendre votre algorithme à partir des commentaires.
flawr
@flawr J'ai ajouté une explication de mon algorithme.
Jakube
@Jaketube Merci pour l'explication, j'aime beaucoup l'approche récursive!
flawr
3

Matlab, 292

Je suis sûr que cela peut être beaucoup raccourci simplement en le portant dans une autre langue.

L'idée de base est le bruteforcing: j'ai trouvé une sorte d'énumération de toutes les façons de placer m*n/2des briques domino sur une m*nplanche. Mais cette énumération comprend également de nombreux pavages invalides (des briques qui se chevauchent ou sortent du tableau). Le programme construit donc tous ces pavages et ne compte que les pavés valides. La complexité d'exécution est sur le point O(2^(m*n/2) * m*n). La mémoire n'est pas un problème 8x8car elle n'a besoin que de O(m*n)mémoire. Mais le temps nécessaire 8x8est d'environ 20 jours.

Voici la version entièrement commentée qui explique ce qui se passe.

PS: Si quelqu'un sait comment faire fonctionner la surbrillance de la syntaxe Matlab, veuillez inclure la balise correspondante dans cette réponse!

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

Voici celui entièrement golfé:

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
flawr
la source
2

C89, 230 octets

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);}

Pour plus de lisibilité, j'ai enveloppé cette réponse à la main - toutes les nouvelles lignes peuvent être supprimées en toute sécurité pour atteindre 230 octets.

Définit une fonction int g(int n, int m)qui renvoie le nombre de pavages. Il utilise une fonction d'assistance fqui itère sur tous les pavages valides en plaçant un domino, récursif, puis en supprimant le domino sur une carte partagée.

orlp
la source
0

Python 243

J'ai opté pour une approche par force brute:

  • générer m * n / 2 directions;
  • essayez de placer le domino sur la carte m * n.

S'ils correspondent tous et qu'il ne reste aucun espace, nous avons une entrée valide.

Voici le code:

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
la source