Tetti di mattoni unici all'interno di un rettangolo


13

Stavo sfogliando Stackoverflow e ho visto questa domanda sulla piastrellatura di un rettangolo MxN e ho pensato che sarebbe stato ottimo per giocare a golf. Ecco il compito.

Date le dimensioni M e N, scrivi un programma che mostri in quanti modi unici un rettangolo MxN (N è il numero di righe, non colonne. Non che sia davvero importante) può essere piastrellato dati questi vincoli.

  1. Tutte le tessere sono 2x1 o 3x1
  2. Tutte le tessere rimangono all'interno della loro fila (cioè sono tutte orizzontali)
  3. Tra ogni due file adiacenti le piastrelle non devono essere allineate, tranne che sulle due estremità
  4. M e N sono garantiti almeno 1

Ad esempio, sarebbe una piastrellatura valida di una matrice 8x3

  2    3     3
  |    |     |
  v    v     v
 _______________
|___|_____|_____| 
|_____|_____|___|
|___|_____|_____|

Ma quanto segue non sarebbe valido, poiché le righe si allineano

  2    3     3
  |    |     |
  v    v     v
 _______________
|___|_____|_____| 
|_____|___|_____|
|_____|_____|___|

Casi test:

8x3: 4

3x1: 1

1x1: 0

9x4: 10

Codice golf, quindi vince la risposta più breve.


2
La tua descrizione delle dimensioni delle tessere sembra usare una convenzione diversa dalle dimensioni del rettangolo. Le tessere sono effettivamente 2x1o 3x1? Inoltre è l'output per 4x1zero?
FryAmTheEggman

1
Benvenuto. Bel concetto di sfida, tuttavia di solito è meglio usare la sandbox per elaborare idee di sfida prima di pubblicarle in main.
Beefster

@FryAmTheEggman Sembra che OP abbia cercato di |non contribuire alla lunghezza della riga, usando una rappresentazione come questa (dove, se non c'è una pipe ( |), c'è uno spazio).
Erik the Outgolfer


1
La domanda di riferimento su SO non esiste più.
Arnauld

Risposte:


5

Gelatina , 20 byte

2*ḃ€2‘ÄṪ⁼¥Ƈ⁸ṗfƝẸ$€ċ0

Provalo online!


So che la velocità non faceva parte delle specifiche, ma questo è scaduto anche su 11x10 quando eseguito su tio. Sarei interessato a una spiegazione per capire il perché.
Nick Kennedy,

@NickKennedy È un input troppo grande. Per la larghezza 11, ogni riga può avere uno dei 9 diversi massimali. Per larghezza 11 e altezza 10, ci sono 9¹⁰ = 3486784401 pareti possibili, comprese quelle non valide. Ecco come funziona il potere cartesiano. Ovviamente, TIO non ha il tempo di lasciare che la mia soluzione calcoli l'intera gamma di pareti (scade dopo 60 secondi). Aggiungerò una spiegazione quando avrò il tempo di.
Erik the Outgolfer

Grazie. Ho guardato un po 'la gelatina, ma al momento faccio affidamento su spiegazioni commentate per capire cosa fa il codice delle persone. Avevo ipotizzato, dato il problema del tempo, che il tuo codice bruto forza la soluzione, che è un modo ragionevole di ridurre al minimo i requisiti del codice.
Nick Kennedy,

Per interesse ho ricreato in Jelly il metodo nel mio codice R usando la prima parte del tuo codice. È a Provalo online! e mentre è considerevolmente più lungo del tuo, gestisce numeri più grandi. Nota che al momento non gestisce correttamente 1 riga. Sospetto che potrebbe essere molto più conciso, ma sono nuovo di Jelly.
Nick Kennedy,

4

JavaScript (ES6),  119 110 106 96  91 byte

(N,M)

f=(n,m,p=0,g=(w,h=x=>g(p[g[w-=x]=1,w]||w)*g[w]--)=>w>3?h(2)+h(1):w>1&&f(n,m-1,g))=>m?g(n):1

Provalo online!

Commentate

gfhg

f = (                    // f is a recursive function taking:
  n,                     //   n = number of columns
  m,                     //   m = number of rows
  p = 0,                 //   p = object holding the previous row
  g = (                  //   g = recursive function taking:
    w,                   //     w = remaining width that needs to be filled in the
                         //         current row
    h = x =>             //     h = helper function taking x
                         // h body:
      g(                 //   recursive call to g:
        p[g[w -= x] = 1, //     subtract either 2 or 1 from w and mark this width as used
          w              //     test p[w]
        ]                //     pass p[w] if p[w] = 1 (which will force the next iteration
                         //     to fail immediately)
        || w             //     otherwise, pass w
      )                  //   end of recursive call
      * g[w]--           //   then restore g[w] to 0
  ) =>                   // g body:
    w > 3 ?              //   if w > 3, we need to insert at least 2 more bricks:
      h(2) + h(1)        //     invoke h with x = 2 and x = 1
    :                    //   else:
      w > 1              //     this is the last brick; we just check if it can be inserted
      &&                 //     abort if w is equal to 1 (a brick does not fit in there)
      f(                 //     otherwise, do a recursive call to f:
        n,               //       n is unchanged
        m - 1,           //       decrement m
        g                //       pass g as the new reference row
      )                  //     end of recursive call
) =>                     // f body:
  m ? g(n) : 1           //   yield 1 if we made it to the last row or call g otherwise

1

R , 243 231 byte

function(m,n,i=2*0:(m%/%6)+m%%2,j=i+(m-3*i)/2,M=Map)`if`(m<2,0,sum((e=eigen(lengths(outer(p<-unlist(M(M,list(function(x,y)cumsum(2+1:y%in%x)),M(combn,j,i,s=F),j),F),p,Vectorize(intersect)))<2))$ve%*%diag(e$va^(n-1))%*%solve(e$ve)))

Provalo online!

Versione con interruzioni di riga:

function(m,n,i=2*0:(m%/%6)+m%%2,j=i+(m-3*i)/2,M=Map)`if`(m<2,0,
sum((e=eigen(lengths(outer(p<-unlist(M(M,list(function(x,y)cumsum(2+1:y%in%x)),
M(combn,j,i,s=F),j),F),p,Vectorize(intersect)))<2))$ve%*%diag(e$va^(n-1))%*%solve(e$ve)))

Nota nessuna ricorsione e gestisce valori abbastanza grandi di m e n (ad esempio 24x20 -> 3.3e19)

Ecco una risposta commentata che funziona più o meno come sopra, ma ho annullato tutte le funzioni, quindi è effettivamente leggibile:

f <- function(m,n) {
  # First work out what potential combinations of 2s and 3s add up to m
  i <- 2*0:(m %/% 6) + m %% 2 # Vector with numbers of possible 3s
  j <- i + (m - 3 * i) / 2 # Vector with total number of 2s and 3s
  if (m < 2) {
    0 # If wall less than 2 wide, no point in continuing because answer is 0
  } else {
    # Work out all possible positions of threes for each set
    positions_of_threes <- Map(combn, j, i, simplify = FALSE)
    # Function to work out the cumulative distance along the wall for a given
    # Set of three positions and number of bricks
    make_cumulative_bricks <- function(pos_threes, n_bricks) {
      bricks <- 1:n_bricks %in% pos_threes
      cumsum(2 + bricks)
    }
    # Find all possible rows with cumulative width of wall
    # Note because this is a `Map` with depth two that needs to be vectorised
    # for both `positions_of_threes` and `j`, and we're using base R, the
    # function `make_cumulative_bricks` needs to be placed in a list
    cum_bricks <- Map(Map, list(make_cumulative_bricks), positions_of_threes, j)
    # Finally we have the list of possible rows of bricks as a flat list
    cum_bricks_unlisted <- unlist(cum_bricks, recursive = FALSE)
    # Vectorise the intersect function
    intersect_v <- Vectorize(intersect, SIMPLIFY = FALSE)
    # Find the length of all possible intersects between rows
    intersections <- outer(cum_bricks_unlisted, cum_bricks_unlisted, intersect_v)
    n_intersections <- lengths(intersections)
    # The ones not lined up will only have a single intersect at `m`
    not_lined_up <- n_intersections == 1
    # Now use method described at /programming//a/9459540/4998761
    # to calculate the (matrix of TRUE/FALSE for lined-up) to the power of `n`
    eigen_nlu <- eigen(not_lined_up)
    final_mat <- eigen_nlu$vectors %*%
      diag(eigen_nlu$values ^ (n - 1)) %*%
      solve(eigen_nlu$vectors)
    # The sum of this matrix is what we're looking for
    sum(final_mat)
  }
}
f(20,20)

Il metodo per prendere una matrice e moltiplicarla ripetutamente da solo è una domanda su StackOverflow . Questo approccio funziona qui perché calcola efficacemente il numero cumulativo di rami attraverso le diverse possibili file di mattoni.

Se sono consentiti pacchetti esterni, posso portarlo fino a 192:

function(m,n,i=2*0:(m%/%6)+m%%2,j=i+(m-3*i)/2,M=purrr::map2)`if`(m<2,0,sum(expm::`%^%`(lengths(outer(p<-unlist(M(M(j,i,combn,s=F),j,M,~cumsum(2+1:.y%in%.)),F),p,Vectorize(intersect)))<2,n-1)))

1

Gelatina , 26 byte

2*ḃ€2‘ÄṪ⁼¥Ƈ⁸œ&L¬ɗþ`æ*⁴’¤SS

Provalo online!

Suddiviso:

Genera un elenco di possibili muri come somme cumulative con l'estremità rimossa:

2*ḃ€2‘ÄṪ⁼¥Ƈ⁸

Trova il tavolo esterno di tutti i possibili muri uno contro l'altro che non ha intersezioni:

œ&L¬ɗþ`

Porta questa matrice alla potenza di (N-1) e poi riassumi tutto:

æ*⁴’¤SS

Utilizza il primo bit della risposta di @EriktheOutgolfer per generare l'elenco di possibili muri, quindi utilizza l'intersezione matrice e l'approccio di esponenziazione matrice dalla mia risposta R. Come tale, funziona bene anche con grandi N. Questa è la mia prima risposta di Jelly e sospetto che possa essere giocata più a golf. Idealmente, vorrei anche modificare la prima sezione in modo che i requisiti di tempo e memoria non si ridimensionino in modo esponenziale con M.


0

05AB1E , 42 byte

Åœʒ23yåP}€œ€`Ùε.¥¦¨}IиI.ÆÙεøyíø‚€€üQOO_P}O

Mi vergogno quasi troppo per postare questo, e può sicuramente essere giocato a golf da MOLTO con un approccio diverso, ma dato che ci è voluto un po 'per completarlo, ho deciso di pubblicarlo comunque e giocarlo da qui. La sfida sembra più semplice di quanto non sia imo, ma sto sicuramente usando un approccio sbagliato qui e ho la sensazione che 05AB1E potrebbe fare circa 25 byte ..

Provalo online. NOTA: non solo è lungo, ma è anche inefficiente, poiché il 9x4caso di test viene eseguito in circa 40 secondi su TIO ..

Spiegazione:

Ŝ             # Get all possible ways to sum to the (first) implicit input
               #  i.e. 8 → [[1,1,1,1,1,1,1,1],[1,1,1,1,1,1,2],[1,1,1,1,1,3],[1,1,1,1,2,2],[1,1,1,1,4],[1,1,1,2,3],[1,1,1,5],[1,1,2,2,2],[1,1,2,4],[1,1,3,3],[1,1,6],[1,2,2,3],[1,2,5],[1,3,4],[1,7],[2,2,2,2],[2,2,4],[2,3,3],[2,6],[3,5],[4,4],[8]]
  ʒ23yåP}      # Only leave those consisting of 2s and/or 3s
               #  → [[2,2,2,2],[2,3,3]]
         €œ    # For each: get all permutations
           €`  # Flatten this list of lists once
             Ù # And uniquify it (leaving all possible distinct rows of bricks)
               #  → [[2,2,2,2],[3,3,2],[3,2,3],[2,3,3]]
ε    }         # For each:
             #  Get the cumulative sum
   ¦¨          #  With the leading 0 and trailing first input removed
               #   → [[2,4,6],[3,6],[3,5],[2,5]]
      Iи       # Repeat this list the second input amount of times
               #  i.e. 3 → [[2,4,6],[3,6],[3,5],[2,5],[2,4,6],[3,6],[3,5],[2,5],[2,4,6],[3,6],[3,5],[2,5]]
        I    # Get all combinations of lists the size of the second input
           Ù   # And uniquify the result (leaving all possible distinct walls)
               #  → [[[2,4,6],[3,6],[3,5]],[[2,4,6],[3,6],[2,5]],[[2,4,6],[3,6],[2,4,6]],[[2,4,6],[3,6],[3,6]],[[2,4,6],[3,5],[2,5]],[[2,4,6],[3,5],[2,4,6]],[[2,4,6],[3,5],[3,6]],[[2,4,6],[3,5],[3,5]],[[2,4,6],[2,5],[2,4,6]],[[2,4,6],[2,5],[3,6]],[[2,4,6],[2,5],[3,5]],[[2,4,6],[2,5],[2,5]],[[2,4,6],[2,4,6],[3,6]],[[2,4,6],[2,4,6],[3,5]],[[2,4,6],[2,4,6],[2,5]],[[2,4,6],[2,4,6],[2,4,6]],[[3,6],[3,5],[2,5]],[[3,6],[3,5],[2,4,6]],[[3,6],[3,5],[3,6]],[[3,6],[3,5],[3,5]],[[3,6],[2,5],[2,4,6]],[[3,6],[2,5],[3,6]],[[3,6],[2,5],[3,5]],[[3,6],[2,5],[2,5]],[[3,6],[2,4,6],[3,6]],[[3,6],[2,4,6],[3,5]],[[3,6],[2,4,6],[2,5]],[[3,6],[2,4,6],[2,4,6]],[[3,6],[3,6],[3,5]],[[3,6],[3,6],[2,5]],[[3,6],[3,6],[2,4,6]],[[3,6],[3,6],[3,6]],[[3,5],[2,5],[2,4,6]],[[3,5],[2,5],[3,6]],[[3,5],[2,5],[3,5]],[[3,5],[2,5],[2,5]],[[3,5],[2,4,6],[3,6]],[[3,5],[2,4,6],[3,5]],[[3,5],[2,4,6],[2,5]],[[3,5],[2,4,6],[2,4,6]],[[3,5],[3,6],[3,5]],[[3,5],[3,6],[2,5]],[[3,5],[3,6],[2,4,6]],[[3,5],[3,6],[3,6]],[[3,5],[3,5],[2,5]],[[3,5],[3,5],[2,4,6]],[[3,5],[3,5],[3,6]],[[3,5],[3,5],[3,5]],[[2,5],[2,4,6],[3,6]],[[2,5],[2,4,6],[3,5]],[[2,5],[2,4,6],[2,5]],[[2,5],[2,4,6],[2,4,6]],[[2,5],[3,6],[3,5]],[[2,5],[3,6],[2,5]],[[2,5],[3,6],[2,4,6]],[[2,5],[3,6],[3,6]],[[2,5],[3,5],[2,5]],[[2,5],[3,5],[2,4,6]],[[2,5],[3,5],[3,6]],[[2,5],[3,5],[3,5]],[[2,5],[2,5],[2,4,6]],[[2,5],[2,5],[3,6]],[[2,5],[2,5],[3,5]],[[2,5],[2,5],[2,5]]]
ε              # Map all walls `y` to:
 ø             #  Zip/transpose; swapping rows and columns
 yí            #  Reverse each row in a wall `y`
   ø           #  Also zip/transpose those; swapping rows and columns
              #  Pair both
              #  For both:
              #   For each column:
    ü          #    For each pair of bricks in a column:
     Q         #     Check if they are equal to each other (1 if truthy; 0 if falsey)
    O          #    Then take the sum of these checked pairs for each column
   O           #   Take the sum of that entire column
   _           #   Then check which sums are exactly 0 (1 if 0; 0 if anything else)
   P           #   And check for which walls this is only truthy by taking the product
}O             # After the map: sum the resulting list
               # (and output it implicitly as result)

0

Carbone , 89 byte

Nθ⊞υ⟦⟧≔⟦⟧ηFυF⟦²¦³⟧«≧⁺∧Lι§ι⁰κ¿⁼κθ⊞ηι¿‹κθ⊞υ⁺⟦κ⟧ι»≔Eη⟦ι⟧ζF⊖N«≔ζι≔⟦⟧ζFιFη¿¬⊙§κ⁰№λμ⊞ζ⁺⟦λ⟧κ»ILζ

Provalo online! Il collegamento è alla versione dettagliata del codice. Funziona con rettangoli di dimensioni fino a circa 12 su TIO, ma potrebbe essere reso circa tre volte più veloce al costo di 2 byte usando il bit twiddling anziché l'intersezione dell'elenco. Spiegazione:

Nθ

Inserisci la larghezza.

⊞υ⟦⟧

Inizia con una riga senza mattoni.

≔⟦⟧η

Inizia senza righe completate.

Fυ

Passa sopra le file.

F⟦²¦³⟧«

Passa sopra i mattoni.

≧⁺∧Lι§ι⁰κ

Aggiungi la larghezza del mattone alla larghezza della riga corrente.

¿⁼κθ⊞ηι

Se ciò comporta la larghezza di input, aggiungere questa riga all'elenco delle righe completate.

¿‹κθ⊞υ⁺⟦κ⟧ι»

Altrimenti, se questa è ancora inferiore alla larghezza di input, aggiungi la nuova riga all'elenco di righe, facendola così raccogliere da una successiva iterazione.

≔Eη⟦ι⟧ζ

Crea un elenco di pareti di una riga.

F⊖N«

Passa sopra uno in meno dell'altezza.

≔ζι

Salva l'elenco dei muri.

≔⟦⟧ζ

Cancella l'elenco dei muri.

Fι

Scorri l'elenco delle pareti salvate.

Fη

Passa sopra le righe completate.

¿¬⊙§κ⁰№λμ⊞ζ⁺⟦λ⟧κ»

Se la riga può essere aggiunta a questo muro, aggiungilo all'elenco dei muri.

ILζ

Stampa la lunghezza dell'elenco finale dei muri.

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.