Numero di tetti domino


9

Scrivere un programma o una funzione che dato positivo n e m calcola il numero di valide tassellature distinti domino si può stare in una n per m rettangolo. Questa è la sequenza A099390 nel enciclopedia online di Integer Sequences . Puoi inserire input come argomenti di funzione, CLA o su stdin, in qualsiasi formato ragionevole. È necessario restituire o stampare un singolo numero intero come output.

Ogni piastrellatura non deve lasciare spazi vuoti e viene contata ogni piastrellatura distinta, comprese rotazioni, riflessioni, ecc. Ad esempio, i tasselli per 2x3 sono:

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

Esempi di ingressi / uscite:

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

Il tuo programma dovrebbe teoricamente funzionare per qualsiasi n e m , ma se il tuo programma richiede troppa memoria o il tuo tipo di dati trabocca è scusato. Tuttavia, il programma deve funzionare correttamente per qualsiasi n, m <= 8.


Vince il codice più breve in byte.


Avresti potuto rendere la nostra vita molto più semplice se avessi permesso solo aree 2n x 2m , bella sfida!
flawr

Proprio come questa domanda codegolf.stackexchange.com/q/51067/15599 solo più corto e più lento
Level River St

@ edc65 Damnit = / Non riesco a pensare a nulla di nuovo ... Quasi tutte le sfide a cui penso sono già state fatte in qualche modo. Ad ogni modo, le sfide non sono esattamente le stesse poiché la mia domanda è un codice golf, e non devi trovare i limiti - solo la quantità di essi. Forse le persone possono usare formule carine invece di scrivere un bruteforcer.
orlp

D'accordo - andando a rimuovere l'altro commento
edc65

Il commento di bilbo copiato (che ha pubblicato come risposta a causa di 1 rappresentante): "Questo problema è una riduzione SPOJ abbreviata: spoj.com/problems/MNTILE Il codice più breve su SPOJ è 98 byte in awk". . Sembra che io sia doppiamente non originale - non ero a conoscenza.
orlp,

Risposte:


3

Pyth, 30 29 byte

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

Provalo online: Dimostrazione / Test Suite

Tutti gli input di esempio vengono eseguiti nel compilatore online. L'ultimo richiede alcuni secondi.

Spiegazione:

Nel mio codice definirò una funzione ricorsiva y. La funzione yprende un elenco di coordinate 2D e restituisce il numero di diversi tetti domino usando queste coordinate. Ad esempio y([[0,0], [0,1]]) = 1(un domino orizzontale), y([[0,0], [1,1]]) = 0(le coordinate non sono adiacenti) e y([[0,0], [0,1], [1,0], [1,1]]) = 2(due domino orizzontali o due verticali). Dopo aver definito la funzione, la chiamerò con tutte le coordinate [x,y]con x in [0, 1, m-1], y in [0, 1, n-1].

Come funziona la funzione ricorsiva? È abbastanza semplice. Se l'elenco dei coords è vuoto, esiste esattamente una piastrellatura e yritorni validi 1.

Altrimenti prendo la prima coordinata nell'elenco b[0]e cerco le coordinate rimanenti per un vicino. Se non è presente un vicino b[0], non è possibile eseguire la piastrellatura, quindi restituisco 0. Se sono presenti uno o più vicini, il numero di tasselli è (il numero di tasselli in cui mi collego b[0]al primo vicino tramite una domina, oltre a il numero di tasselli in cui mi collego b[0]con il secondo vicino, più ...) Quindi chiamo ricorsivamente la funzione per ciascun vicino con l'elenco abbreviato (rimuovendo i due cordoni b[0]e il vicino). Successivamente riassumo tutti i risultati e li restituisco.

A causa dell'ordine dei cordoni ci sono sempre solo due vicini possibili, quello a destra e quello in basso. Ma al mio algoritmo non interessa.

                          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  

Puoi dirci qualcosa in più su come funziona il tuo programma? Non sono riuscito a capire il tuo algoritmo dai commenti.
Flawr

@flawr Ho aggiunto una spiegazione del mio algoritmo.
Jakube,

@Jaketube Grazie per la spiegazione, mi piace molto l'approccio ricorsivo!
Flawr,

3

Matlab, 292

Sono sicuro che questo può essere abbreviato molto semplicemente portandolo in un'altra lingua.

L'idea di base è la forza bruta: mi è venuta in mente una sorta di elenco di tutti i modi in cui posizionare i m*n/2mattoncini di domino su una m*ntavola. Ma questa enumerazione include anche molti massimali non validi (mattoni che si sovrappongono o vanno fuori dal tabellone). Quindi il programma costruisce tutti quei massimali e conta solo quelli validi. La complessità del runtime è di circa O(2^(m*n/2) * m*n). La memoria non è un problema per il 8x8perché ha solo bisogno di O(m*n)memoria. Ma il tempo necessario 8x8è di circa 20 giorni.

Qui la versione completamente commentata che spiega cosa sta succedendo.

PS: Se qualcuno sa come far funzionare l'evidenziazione della sintassi Matlab, includi il tag corrispondente in questa risposta!

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

Ecco quello completamente golfato:

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

Per leggibilità ho racchiuso a mano questa risposta: tutte le nuove righe possono essere rimosse in modo sicuro per arrivare a 230 byte.

Definisce una funzione int g(int n, int m)che restituisce il numero di limiti. Utilizza una funzione di supporto fche scorre su tutti i limiti validi posizionando un domino, ricorrendo e quindi rimuovendo il domino su una scheda condivisa.


0

Python 243

Ho optato per un approccio di forza bruta:

  • generare direzioni m * n / 2;
  • prova a montare il domino sulla scheda m * n.

Se si adattano tutti e non rimangono spazi, abbiamo una voce valida.

Ecco il codice:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.