도미노 타일링 수


9

양수 nm 이 주어진 프로그램이나 함수를 작성하면 n x 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 면적 만 허용 하면 멋진 도전을 할 수 있습니다.
flawr


@ edc65 Damnit = / 나는 전혀 새로운 것을 생각할 수 없다 ... 내가 생각하는 거의 모든 도전은 이미 어떤 형태로 이루어졌다. 어느 쪽이든, 내 질문은 코드 골프이기 때문에 도전 과제는 정확히 동일하지 않으며 타일링을 찾을 필요가 없으며 그 양만 있습니다. 아마도 사람들은 무차별 대입을 쓰는 대신 멋진 공식을 사용할 수 있습니다.
orlp

합의 – 다른 의견을 제거 할 예정
edc65

복사 한 bilbo의 의견 (그가 1 명의 답변으로 답변으로 게시 한 답변) : "이 문제는 SPOJ 챌린지 단축 : spoj.com/problems/MNTILE SPOJ 의 가장 짧은 코드는 awk 단위로 98 바이트입니다." . 내가 독창적이지 않은 것 같습니다-나는 알지 못했습니다.
orlp

답변:


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].

재귀 함수는 어떻게 작동합니까? 아주 간단합니다. 좌표 목록이 비어 있으면 정확히 하나의 유효한 바둑판 식 배열이 있고를 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

@flawr 내 알고리즘에 대한 설명을 추가했습니다.
Jakube

@Jaketube 설명해 주셔서 감사합니다. 저는 재귀 접근법을 정말로 좋아합니다!
flawr

3

MATLAB, 292

다른 언어로 이식하는 것만으로도 이것이 단축 될 수 있다고 확신합니다.

기본 아이디어는 무차별 대입입니다. 저는 보드 m*n/2에 도미노 벽돌 을 배치하는 방법에 대한 모든 종류의 열거를 생각해 냈습니다 m*n. 그러나이 열거에는 유효하지 않은 많은 타일 (보드가 겹치거나 보드 밖으로 나가는 브릭)도 포함됩니다. 따라서 프로그램은 이러한 모든 타일을 구성하고 유효한 타일 만 계산합니다. 런타임 복잡도는 약 O(2^(m*n/2) * m*n)입니다. 메모리는 메모리 8x8만 필요 하기 때문에 문제가되지 않습니다 O(m*n). 그러나 필요한 시간 8x8은 약 20 일입니다.

여기에 무슨 일이 일어나고 있는지 설명하는 완전히 주석이 달린 버전이 있습니다.

추신 : 누구나 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

파이썬 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.