多米诺瓷砖的数量


9

编写一个给定正nm的程序或函数,以计算可以放入n × m矩形中的有效不同多米诺骨牌拼贴的数量。这是序列A099390整数序列的在线百科全书。您可以采用任何合理的格式将输入作为函数参数,CLA或stdin接受。您必须返回或打印单个整数作为输出。

每个平铺块都不得留有任何间隙,并且会计算每个不同的平铺块,包括旋转,反射等。例如,2x3的平铺块为:

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

输入/输出示例:

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

从理论上讲,您的程序应可用于任何nm,但是如果您的程序需要太多内存或数据类型溢出,则可以使用。您的程序必须能正确地工作任何n,但是m <= 8。


以字节为单位的最短代码获胜。


如果只允许2n x 2m的区域,您本可以使我们的生活更加轻松,这是一个不错的挑战!
瑕疵的

就像这个问题一样,codegolf.stackexchange.com/q/51067/15599只会更短,更慢
Level River St

@ edc65 Damnit = /我似乎想不出什么新颖的东西...我想到的几乎所有挑战都已经以某种形式完成。无论哪种方式,挑战都不是完全相同的,因为我的问题是打高尔夫球,而您不必找到平铺-只需找到它们的数量即可。也许人们可以使用漂亮的公式代替编写暴力破解程序。
orlp 2015年

同意-删除其他评论
edc65

复制的bilbo的评论(他因发表1次答辩而作为答复发布):“此问题是SPOJ挑战的简称:spoj.com/problems/MNTILE SPOJ上最短的代码是awk中的98字节。” 。似乎我是双重非原创-我没有意识到。
orlp 2015年

Answers:


3

Pyth,30个 29字节

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

在线试用:演示 / 测试套件

所有示例输入均在联机编译器中运行。最后一个需要几秒钟。

说明:

在我的代码中,我将定义一个递归函数y。该函数y获取2D坐标的列表,并使用这些坐标返回不同的多米诺瓷砖的数量。例如y([[0,0], [0,1]]) = 1(一个水平多米诺骨牌),y([[0,0], [1,1]]) = 0(坐标不相邻)和y([[0,0], [0,1], [1,0], [1,1]]) = 2(两个水平或两个垂直多米诺骨牌)。定义功能后,我会与所有的坐标调用它[x,y]x in [0, 1, m-1], y in [0, 1, n-1]

递归函数如何工作?这很简单。如果坐标列表为空,则只有一个有效的平铺并y返回1

否则,我将获取列表中的第一个坐标b[0],并在其余的坐标中搜索邻居。如果没有邻居b[0],则不可能进行切片,因此我返回0。如果存在一个或多个邻居,则切片数为(通过多米纳b[0]与第一个邻居连接的切片数,加上我b[0]与第二个邻居连接的平铺数,加上...)因此,我以缩短的列表为每个邻居递归调用该函数(通过删除两个坐标b[0]和邻居)。然后,我总结所有结果并将其返回。

由于坐标的顺序,总是只有两个邻居,一个在右边,另一个在下面。但是我的算法不在乎。

                          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  

您能否告诉我们更多有关您的程序如何工作的信息?我无法从评论中找出您的算法。
瑕疵的

@flawr我添加了对算法的解释。
2015年

@Jaketube感谢您的解释,我真的很喜欢递归方法!
flawr

3

Matlab,292年

我相信,只需将其移植到另一种语言中,就可以大大缩短这一时间。

基本思想是暴力破解:我想出了一种如何m*n/2m*n板上放置多米诺骨牌的所有方式的列举。但是,此枚举还包括许多无效的切片(重叠或移出木板的砖块。)因此,程序将构造所有这些切片,并且仅计算有效的切片。运行时复杂度约为O(2^(m*n/2) * m*n)。内存不是问题,8x8因为它只需要O(m*n)内存。但是所需的时间8x8大约是20天。

在这里,完整注释的版本将说明发生了什么。

PS:如果有人知道如何使Matlab语法突出显示,请在此答案中包含相应的标签!

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

这里是打高尔夫球的人:

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

2

C89,230字节

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

出于可读性考虑,我用手工包装了这个答案-可以安全地删除所有换行符以达到230个字节。

定义一个int g(int n, int m)返回平铺数目的函数。它使用一个辅助函数f,该函数通过放置一个多米诺骨牌,递归然后在共享板上删除多米诺骨牌来迭代所有有效的切片。


0

Python 243

我选择了蛮力方法:

  • 产生m * n / 2个方向;
  • 尝试将多米诺骨牌固定在m * n板上。

如果它们都适合并且不留空格,则我们有一个有效的条目。

这是代码:

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.