ドミノタイルの数


9

与えられた正のことのプログラムや関数を書くのnおよびmは、あなたが合うことができる有効な個別のドミノタイリングの数を計算n個m個の四角形を。これはシーケンスであるA099390における整数列のオンライン百科事典。関数の引数、CLA、または標準入力で、適切な形式で入力を受け取ることができます。単一の整数を出力として返すか印刷する必要があります。

各タイリングはギャップを残してはならず、回転、反射などを含むすべての個別のタイリングがカウントされます。たとえば、2x3のタイリングは次のとおりです。

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

入力/出力の例:

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

プログラムは理論的には任意のnおよびmで機能するはずですが、プログラムで必要なメモリが多すぎる場合やデータ型がオーバーフローする場合は、免除されます。ただしプログラムはn、m <= 8 正しく機能する必要があります。


バイト単位の最短コードが優先されます。


2n x 2mのエリアしか許可していなければ、私たちの生活をはるかに楽にすることができたでしょう。
flawr 2015

この質問のようにcodegolf.stackexchange.com/q/51067/15599はより短く、より遅い
Level River St

@ edc65 Damnit = /斬新なことは考えられないようです...私が思うほぼすべての課題は、すでに何らかの形で行われています。どちらの方法でも、私の質問はコードゴルフなので、課題はまったく同じではなく、タイルを見つける必要はありません。タイルの数だけです。たぶん人々はブルートフォーサーを書く代わりに素晴らしい式を使うことができます。
orlp 2015

同意-他のコメントを削除する予定
edc65

(彼は原因1人の担当者への答えとして掲載)コピーされたビルボのコメント:「この問題は短くSPOJの課題です:spoj.com/problems/MNTILE SPOJ上の最短のコードでは、awkでは98バイトです。」。私は二重に独創的ではないようです-私は知らなかった。
orlp 2015

回答:


3

Pyth、30 29バイト

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

オンラインで試す:デモ / テストスイート

すべての入力例は、オンラインコンパイラで実行されます。最後のものは数秒かかります。

説明:

私のコードでは、再帰関数を定義しますy。この関数yは2D座標のリストを取り、これらの座標を使用してさまざまなドミノタイルの数を返します。たとえば、y([[0,0], [0,1]]) = 1(1つの水平ドミノ)、y([[0,0], [1,1]]) = 0(座標が隣接していない)、y([[0,0], [0,1], [1,0], [1,1]]) = 2(2つの水平ドミノまたは2つの垂直ドミノ)。関数を定義した後、すべての座標で[x,y]を呼び出しますx in [0, 1, m-1], y in [0, 1, n-1]

再帰関数はどのように機能しますか?とても簡単です。coordsのリストが空の場合、有効なタイリングは1つだけあり、をy返します1

それ以外の場合は、リストの最初の座標を取得しb[0]、残りの座標から近傍を検索します。へのネイバーがない場合b[0]、タイリングは不可能であるため、0を返します。1つ以上のネイバーがある場合、タイリングの数は(b[0]ドミナを介して最初のネイバーと接続するタイリングの数に加えて、b[0]2番目のネイバーに接続するタイリングの数に加えて...)したがって、(2つの座標b[0]とネイバーを削除することにより)短縮されたリストを使用して、ネイバーごとに関数を再帰的に呼び出します。その後、すべての結果を集計して返します。

座標の順序のため、可能な隣人は常に2つしかありません。1つは右側にあり、もう1つは下にあります。しかし、私のアルゴリズムはそれを気にしません。

                          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

@flawrアルゴリズムの説明を追加しました。
ジャクベ2015

@Jaketube説明ありがとうございます、私は再帰的なアプローチが本当に好きです!
flawr 2015

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)タイリングの数を返す関数を定義します。これは、f1つのドミノを配置して再帰し、共有ボード上のドミノを削除することにより、すべての有効なタイリングを反復するヘルパー関数を使用します。


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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.