Jumlah ubin domino

9

Tulis sebuah program atau fungsi yang diberi n positif dan m menghitung jumlah domino berbeda tilings yang valid yang dapat Anda masukkan dalam persegi panjang n oleh m . Ini adalah urutan A099390 dalam Ensiklopedia Online Urutan Bilangan Bulat . Anda dapat mengambil input sebagai argumen fungsi, CLA atau pada stdin, dalam format apa pun yang masuk akal. Anda harus mengembalikan atau mencetak bilangan bulat tunggal sebagai output.

Setiap ubin tidak boleh meninggalkan celah, dan setiap ubin berbeda dihitung, termasuk rotasi, refleksi, dll. Misalnya, miring untuk 2x3 adalah:

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

Contoh input / output:

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

Program Anda secara teoritis harus bekerja untuk setiap n dan m , tetapi jika program Anda membutuhkan terlalu banyak memori atau tipe data Anda meluap itu dikecualikan. Namun program Anda harus bekerja dengan benar untuk n, m <= 8.


Kode terpendek dalam byte menang.

orlp
sumber
Anda bisa membuat hidup kita jauh lebih mudah jika Anda hanya mengizinkan area 2n x 2m , tantangan bagus!
flawr
Persis seperti pertanyaan ini codegolf.stackexchange.com/q/51067/15599 hanya lebih pendek, dan lebih lambat
Level River St
@ edc65 Damnit = / Sepertinya saya tidak bisa memikirkan novel apa pun ... Hampir setiap tantangan yang saya pikirkan telah dilakukan dalam beberapa bentuk. Either way, tantangannya tidak persis sama karena pertanyaan saya adalah kode golf, dan Anda tidak harus menemukan tilings - hanya jumlahnya. Mungkin orang bisa menggunakan formula yang bagus alih-alih menulis bruteforcer.
orlp
Setuju - akan menghapus komentar lain
edc65
Komentar bilbo yang disalin (yang dia posting sebagai jawaban karena 1 orang): "Masalah ini adalah tantangan SPOJ yang dipersingkat : spoj.com/problems/MNTILE Kode terpendek pada SPOJ adalah 98 byte dalam awk." . Sepertinya saya dua kali lipat tidak orisinal - saya tidak sadar.
orlp

Jawaban:

3

Pyth, 30 29 byte

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

Cobalah online: Demonstration / Test Suite

Semua input contoh dijalankan di kompiler online. Yang terakhir membutuhkan beberapa detik.

Penjelasan:

Dalam kode saya, saya akan mendefinisikan fungsi rekursif y. Fungsi ini ymengambil daftar koordinat 2D dan mengembalikan jumlah dominasi yang berbeda menggunakan koordinat ini. Misalnya y([[0,0], [0,1]]) = 1(satu domino horisontal), y([[0,0], [1,1]]) = 0(koordinat tidak berdekatan) dan y([[0,0], [0,1], [1,0], [1,1]]) = 2(baik dua domino horizontal atau dua). Setelah mendefinisikan fungsi saya akan memanggilnya dengan semua koordinat [x,y]dengan x in [0, 1, m-1], y in [0, 1, n-1].

Bagaimana cara kerja fungsi rekursif? Sederhana saja. Jika daftar coords kosong, hanya ada satu ubin yang valid dan ykembali 1.

Kalau tidak, saya mengambil koordinat pertama dalam daftar b[0], dan mencari tetangga yang tersisa untuk tetangga. Jika tidak ada tetangga untuk b[0], maka tidak ada ubin mungkin, maka saya kembali 0. Jika ada satu atau lebih tetangga, maka jumlah miring adalah (jumlah miring di mana saya terhubung b[0]dengan tetangga pertama melalui domina, ditambah jumlah miring di mana saya terhubung b[0]dengan tetangga kedua, ditambah ...) Jadi saya sebut fungsi secara rekursif untuk setiap tetangga dengan daftar singkat (dengan menghapus dua coord b[0]dan tetangga). Setelah itu saya meringkas semua hasil dan mengembalikannya.

Karena urutan koordinasi selalu hanya ada dua tetangga, satu di sisi kanan dan satu di bawah. Tetapi algoritma saya tidak peduli tentang itu.

                          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
sumber
Bisakah Anda memberi tahu kami sedikit tentang cara kerja program Anda? Saya tidak dapat mengetahui algoritme Anda dari komentar.
flawr
@ flawr Saya menambahkan penjelasan tentang algoritma saya.
Jakube
@Jaketube Terima kasih atas penjelasannya, saya sangat suka pendekatan rekursif!
flawr
3

Matlab, 292

Saya yakin ini bisa dipersingkat banyak hanya dengan porting ke bahasa lain.

Ide dasarnya adalah bruteforcing: Saya datang dengan semacam enumerasi dari semua cara bagaimana menempatkan m*n/2batu bata domino di m*npapan tulis. Tetapi enumerasi ini juga mencakup banyak tilt yang tidak valid (batu bata yang tumpang tindih atau keluar dari papan.) Jadi program ini membangun semua tilings itu, dan hanya menghitung yang valid. Kompleksitas runtime adalah tentang O(2^(m*n/2) * m*n). Memori bukan masalah karena 8x8hanya membutuhkan O(m*n)memori. Tetapi waktu yang dibutuhkan 8x8sekitar 20 hari.

Di sini, versi yang sepenuhnya dikomentari yang menjelaskan apa yang sedang terjadi.

PS: Jika ada yang tahu cara membuat sintaks Matlab berfungsi, harap sertakan tag yang sesuai dalam jawaban ini!

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

Di sini yang sepenuhnya 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
cacat
sumber
2

C89, 230 byte

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

Agar mudah dibaca, saya menulis jawaban ini dengan tangan - semua baris baru dapat dihapus dengan aman hingga mencapai 230 byte.

Menentukan fungsi int g(int n, int m)yang mengembalikan jumlah kemiringan. Ia menggunakan fungsi pembantu fyang mengulangi semua tilings yang valid dengan menempatkan satu domino, berulang, dan kemudian menghapus domino pada papan bersama.

orlp
sumber
0

Python 243

Saya memilih pendekatan brute force:

  • menghasilkan arah m * n / 2;
  • coba dan paskan domino di papan m * n.

Jika semuanya cocok dan tidak ada spasi yang tersisa, kami memiliki entri yang valid.

Ini kodenya:

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
sumber