9
\$\begingroup\$

Write a program or function that given positive n and m calculates the number of valid distinct domino tilings you can fit in a n by m rectangle. This is sequence A099390 in the Online Encyclopedia of Integer Sequences. You may take input in as function argument(s), CLA or on stdin, in any reasonable format. You must return or print a single integer as output.

Each tiling must not leave any gaps, and every distinct tiling is counted, including rotations, reflections, etc. For example, the tilings for 2x3 are:

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

Example inputs/outputs:

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

Your program should theoretically work for any n and m, but if your program requires too much memory or your data type overflows it's excused. Your program must work correctly for any n, m <= 8 however.


Shortest code in bytes wins.

\$\endgroup\$
  • \$\begingroup\$ You could have made our life much easier if you only had allowed 2n x 2m areas, nice challenge! \$\endgroup\$ – flawr Aug 24 '15 at 12:30
  • \$\begingroup\$ Just like this question codegolf.stackexchange.com/q/51067/15599 only shorter, and slower \$\endgroup\$ – Level River St Aug 24 '15 at 12:55
  • \$\begingroup\$ @edc65 Damnit =/ I can't seem to think of anything novel... Almost every challenge I think of has already been done in some form. Either way, the challenges are not exactly the same since my question is a code golf, and you don't have to find the tilings - only the amount of them. Maybe people can use nice formulas instead of writing a bruteforcer. \$\endgroup\$ – orlp Aug 24 '15 at 13:15
  • \$\begingroup\$ Agreed - going to remove the other comment \$\endgroup\$ – edc65 Aug 24 '15 at 13:17
  • \$\begingroup\$ Copied bilbo's comment (which he posted as an answer due to 1 rep): "This problem is a SPOJ challenge shorten: spoj.com/problems/MNTILE The shortest code on SPOJ is 98 bytes in awk.". Seems like I'm doubly unoriginal - I was unaware. \$\endgroup\$ – orlp Aug 24 '15 at 13:25
3
\$\begingroup\$

Pyth, 30 29 bytes

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

Try it online: Demonstration / Test Suite

All example inputs run in the online compiler. The last one takes a few seconds though.

Explanation:

In my code I'll define a recursive function y. The function y takes a list of 2D-coordinates and returns the number of different domino tilings using these coordinates. E.g. y([[0,0], [0,1]]) = 1 (one horizontal domino), y([[0,0], [1,1]]) = 0 (coordinates are not adjacent) and y([[0,0], [0,1], [1,0], [1,1]]) = 2 (either two horizontal or two vertical dominoes). After defining the function I'll call it with all coordinates [x,y] with x in [0, 1, m-1], y in [0, 1, n-1].

How does the recursive function work? It's quite simple. If the list of coords is empty, there is exactly one valid tiling and y returns 1.

Otherwise I take the first coordinate in the list b[0], and search the remaining coordinates for a neighbors. If there is no neighbor to b[0], then there is no tiling possible, therefore I return 0. If there is one or more neighbors, then the number of tilings is (the number of tilings where I connect b[0] with the first neighbor via a domina, plus the number of tilings where I connect b[0] with the second neighbor, plus ...) So I call the function recursively for each neighbor with the shortened list (by removing the two coords b[0] and neighbor). Afterwards I sum up all results and return them.

Because of the order of the coords there are always only two neighbors possible, the one on the right side and the one below. But my algorithm doesn't care about that.

                          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  
\$\endgroup\$
  • \$\begingroup\$ Can you tell us a little bit more about how your program works? I could not figure out your algorithm from the comments. \$\endgroup\$ – flawr Aug 25 '15 at 18:16
  • \$\begingroup\$ @flawr I added an explanation of my algorithm. \$\endgroup\$ – Jakube Aug 26 '15 at 6:51
  • \$\begingroup\$ @Jaketube Thanks for the explanation, I really like the recursive approach! \$\endgroup\$ – flawr Aug 26 '15 at 12:50
3
\$\begingroup\$

Matlab, 292

I am sure this can be shortened a lot just by porting it into another language.

The basic idea is bruteforcing: I came up with kind of an enumeration of all ways how to place m*n/2 domino bricks on an m*n board. But this enumeration also includes many invalid tilings (bricks that overlap or go outside of the board.) So the program constructs all those tilings, and only counts the valid ones. The runtime complexity is about O(2^(m*n/2) * m*n). Memory is not a problem for the 8x8 as it only needs O(m*n) memory. But the time needed for 8x8 is about 20 days.

Here the fully commented version that explains what is going on.

PS: If anyone knows how to make the Matlab syntax highlighting work, please include the corresponding tag in this answer!

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

Here the fully golfed one:

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
\$\endgroup\$
2
\$\begingroup\$

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

For readability I handwrapped this answer - all newlines can safely be removed to get to 230 bytes.

Defines a function int g(int n, int m) that returns the number of tilings. It uses a helper function f that iterates over all valid tilings by placing one domino, recursing, and then removing the domino on a shared board.

\$\endgroup\$
0
\$\begingroup\$

Python 243

I opted for a brute force approach:

  • generate m*n/2 directions;
  • try and fit the domino on the m*n board.

If they all fit and no spaces are left we have a valid entry.

Here is the 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
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.