Partizionare la griglia in triangoli


18

Obbiettivo

L'obiettivo di questa sfida è produrre una funzione nche calcoli il numero di modi per suddividere la n X 1griglia in triangoli in cui tutti i vertici dei triangoli si trovano su punti della griglia.

Esempio

Ad esempio, ci sono 14 modi per partizionare la griglia 2 x 1, quindi f(2) = 14tramite le seguenti partizioni in Partizioni di 2 x 1 cui le partizioni hanno rispettivamente 2, 2, 2, 2, 4 e 2 orientamenti distinti.

punteggio

Questo è , quindi vince il codice più corto.


10
Alcuni casi di test aggiuntivi potrebbero essere utili, quindi possiamo verificare che i nostri invii siano corretti.
AdmBorkBork,

8
Potresti voler specificare triangoli non degeneri .
Arnauld,

1
Ho apportato modifiche alla sequenza OEIS A051708 per riflettere questa interpretazione.
Peter Kagey,

Risposte:


2

05AB1E , 13 byte

·LÉœÙεÅγo;P}O

La risposta di Port of Jelly a @Bubbler .

Molto lento a causa delle permutazioni incorporate.

Provalo online o verifica i primi quattro input .

Spiegazione:

·                # Double the (implicit) input
 L               # Create a list in the range [1, doubled_input]
  É              # Check for each if they're odd (1 if truthy, 0 is falsey)
                 # We now have a list of n 0s and n 1s (n being the input)
   œ             # Get all permutations of that list
    Ù            # Only leave the unique permutations
     ε     }     # Map each permutation to:
      Åγ         #  Run-length encode the current value (short for `γ€g`)
        o        #  Take 2 to the power for each
         ;       #  Halve each
          P      #  Take the product of the mapped permutation
            O    # Sum all mapped values together (and output implicitly)

19

Haskell , 60 55 54 52 byte

Dopo aver disegnato e programmato molti esempi, mi è venuto in mente che questo è lo stesso del problema delle torri:

Su una scacchiera (n+1)×(n+1) , quanti modi ci sono per far passare una torre da (0,0) a (n,n) semplicemente spostandosi verso destra +(1,0) o verso l'alto +(0,1) ?

Fondamentalmente hai la linea superiore e inferiore della griglia 1×n . Ora devi compilare la linea non orizzontale. Ogni triangolo deve avere due linee non orizzontali. Se uno dei suoi lati fa parte della linea superiore o inferiore corrisponde alla direzione e alla lunghezza in cui andresti nel problema delle torri. Questo è OEIS A051708 . Come esempio di questa corrispondenza, prendere in considerazione i seguenti esempi. Qui la linea superiore corrisponde ai movimenti verso l'alto, mentre la linea inferiore corrisponde ai movimenti verso destra.

Grazie @PeterTaylor per -6 byte e @PostLeftGarfHunter per -2 byte!

b 0=1
b 1=2
b n=div((10*n-6)*b(n-1)-9*(n-2)*b(n-2))n

Provalo online!


Ho trovato la sequenza OEIS cercando con i primi pochi valori. Bella spiegazione del perché corrisponde. Vuoi modificarlo per aggiungere un commento su questa interpretazione combinatoria alternativa? Altrimenti, potrei.
Peter Taylor,

A proposito, è necessario regolare l'indicizzazione, perché la risposta corretta qui è A051708(n+1). Quindi ho pubblicato la prima risposta corretta :-P
Peter Taylor

Immagino che la torre muova la mappa verso i triangoli facendo triangoli con i bordi superiore e inferiore corrispondenti alle mosse verso l'alto o verso destra?
Neil,

@PeterTaylor Damn, grazie per aver segnalato il mio errore :)
rovinato il

5
@Neil ho aggiunto una spiegazione grafica.
Flawr,

8

Haskell , 42 byte

0?0=1
a?b=sum[a?i+i?a|i<-[0..b-1]]
f n=n?n

Provalo online!

Un'implementazione abbastanza diretta che ricorre su 2 variabili.

Ecco come possiamo ottenere questa soluzione. Inizia con il codice che implementa una formula ricorsiva diretta:

54 byte

0%0=1
a%b=sum$map(a%)[0..b-1]++map(b%)[0..a-1]
f n=n%n

Provalo online!

utilizzando l'interpretazione rook mossa di flawr , a%bè il numero di percorsi che ottengono la torre da (a,b)a (0,0), utilizzando muove solo la diminuzione una coordinata. La prima mossa diminuisce ao diminuisce b, mantenendo l'altra uguale, quindi la formula ricorsiva.

49 byte

a?b=sum$map(a%)[0..b-1]
0%0=1
a%b=a?b+b?a
f n=n%n

Provalo online!

Possiamo evitare la ripetizione map(a%)[0..b-1]++map(b%)[0..a-1]osservando che le due metà sono uguali ae bscambiate. La chiamata ausiliariaa?b conta i percorsi in cui diminuisce la prima mossa a, quindi b?aconta quelli in cui diminuisce la prima mossa b. Questi sono generalmente diversi e si aggiungono a a%b.

La sintesi in a?bpuò anche essere scritta come una comprensione della lista a?b=sum[a%i|i<-[0..b-1]].

42 byte

0?0=1
a?b=sum[a?i+i?a|i<-[0..b-1]]
f n=n?n

Provalo online!

Alla fine, ci liberiamo %e scriviamo semplicemente la ricorsione in termini di? sostituendola a%icon a?i+i?anella chiamata ricorsiva.

Il nuovo caso base fa sì che questo ?dia un output doppio rispetto a quello della versione ?a 49 byte, poiché con 0?0=1, avremmo 0%0=0?0+0?0=2. Ciò consente di definire f n=n?nsenza il dimezzamento che gli altri dovrebbero fare.


La tua soluzione a 49 byte utilizza la stessa ricorsione della mia risposta, ma non ho ancora capito quello a 42 byte. Una spiegazione sarebbe buona.
Peter Taylor,

Penso di aver usato lo stesso approccio in uno dei miei programmi precedenti: l'idea sta generando (o contando) tutte le partizioni generando le linee non orizzontali da destra a sinistra. Si inizia con la linea verticale. Quindi puoi ricorrere: Prendi uno dei nodi finali della linea precedente e collegalo a un nodo sulla linea orizzontale opposta che è più a sinistra di tutti i nodi precedenti su questa linea.
Flawr,

L'operatore a%bconta il numero di partizioni utilizzando i nodi 0,1,...,anella riga superiore e i nodi 0,1,..,bnella riga inferiore. L'operatore a?bconta il numero di modi in cui è possibile aggiungere una nuova riga dal nodo superiore ase il nodo inferiore bè già in uso. (È possibile connettersi aa tutti i nodi [0,1,...,b-1], ma è necessario ricorrere a ciascuno di essi.)
flawr

@flawr, è quello a 49 byte, che capisco. È quello ?di 42 byte che non ho, e ciò che è particolarmente curioso è che non è simmetrico.
Peter Taylor,

@PeterTaylor Scusate la confusione, in qualche modo ho confuso le due soluzioni. Penso che possiamo facilmente trasformare le due soluzioni l'una nell'altra: nel primo passo possiamo sostituire map...con una comprensione dell'elenco, nel secondo passo inseriamo semplicemente la definizione di %:a?b=sum$map(a%)[0..b-1], a%b=a?b+b?a a?b=sum[a%i|i<-[0..b-1]], a%b=a?b+b?a a?b=sum[a?i+i?a|i<-[0..b-1]]
Flawr,

7

CJam (24 byte)

{2,*e!{e`0f=:(1b2\#}%1b}

Demo online

Questo utilizza l'approccio di Bubbler di sommare le permutazioni di n0 e n1.

Dissezione

{         e# Define a block
  2,*     e#   Given input n, create an array of n 0s and n 1s
  e!      e#   Generate all permutations of that array
  {       e#   Map:
    e`    e#     Run-length encode
    0f=:( e#     Extract just the lengths and decrement them
    1b    e#     Sum
    2\#   e#     Raise 2 to the power of that sum
  }%
  1b      e#  Sum the mapped values
}

Approccio alternativo (28 byte)

{_1aa{_2$,f{j}@@,f{j}+1b}2j}

Demo online

Dissezione

I triangoli hanno tutti un bordo orizzontale e due bordi che collegano le linee orizzontali. Etichettare i bordi non orizzontali di una tupla dei loro due x-coords e ordinare lessicograficamente. Quindi il primo bordo è (0,0), l'ultimo è (n,n)e due bordi consecutivi differiscono esattamente in una delle due posizioni. Questo rende semplice una ricorsione, che ho implementato usando l'operatore di ricorsione memorizzato j:

{            e# Define a block
  _          e#   Duplicate the argument to get n n
  1aa        e#   Base case for recursion: 0 0 => 1
  {          e#   Recursive body taking args a b
    _2$,f{j} e#     Recurse on 0 b up to a-1 b
    @@,f{j}  e#     Recurse on a 0 up to a b-1
    +1b      e#     Combine and sum
  }2j        e#   Memoised recursion with 2 args
}

Nota

Questa non è la prima volta che voglio fjessere supportato in CJam. Qui porterebbe il punteggio anche a 24 byte. Forse dovrei provare a scrivere una patch ...


Sì, ti ho battuto per 10 secondi, non credo di essere mai stato così vicino :)
Flawr,

@flawr, ho preso in considerazione l'idea di postare prima di scrivere una dissezione, ma ho pensato di avere il tempo di eliminarlo rapidamente. Poi ho visto "Nuova risposta", quindi ho eliminato la mia dissezione scritta, pubblicata e modificata.
Peter Taylor,

1
Grazie per -5 byte a proposito: D
flawr

4

Gelatina , 15 14 byte

Ø.xŒ!QŒɠ€’§2*S

Provalo online!

-1 byte basato sul commento di Peter Taylor.

Utilizza direttamente l'illustrazione di flawr , anziché la formula risultante.

Come funziona

Ø.xŒ!QŒɠ€’§2*S    Main link (monad). Input: positive integer N.
Ø.x               Make an array containing N zeros and ones
   Œ!Q            All unique permutations
      Œɠ€         Run-length encode on each permutation
         ’§       Decrement and sum each
           2*S    Raise to power of 2 and sum

Prendi ogni possibile percorso su una griglia quadrata. Il numero di modi per spostare le unità L in una direzione come una torre è 2**(L-1). Applicalo a ogni percorso e somma il numero di modi per attraversare ogni percorso.


Bel approccio. Quando l'ho portato su CJam è stato più breve diminuire le lunghezze, sommare e quindi aumentare 2 alla somma; piuttosto che aumentare 2 della lunghezza, dimezzare e quindi moltiplicare. Non so se potrebbe salvarti un byte.
Peter Taylor,

3

Carbone , 44 31 byte

barrato 44 è ancora regolare 44

F⊕θ«≔⟦⟧ηF⊕θ⊞ηΣ∨⁺ηEυ§λκ¹⊞υη»I⊟⊟υ

Provalo online! Spiegazione: Funziona calcolando il numero di modi per partizionare un trapezio di lunghezze dei lati opposti m,nin triangoli che si trovano tutti su offset interi. Questo è semplicemente un caso generale del rettangolo di dimensioni nnella domanda. Il numero di partizioni è dato in modo ricorsivo come somma dei numeri di partizioni per tutti i lati m,0..n-1e n,0..m-1. Ciò equivale al problema generalizzato delle torri , OEIS A035002 . Il codice calcola semplicemente il numero di partizioni che funzionano 0,0fino n,nall'utilizzo dei valori calcolati in precedenza.

F⊕θ«

Passa sopra le file 0..n.

≔⟦⟧η

Inizia con una riga vuota.

F⊕θ

Passa sopra le colonne della riga 0..n.

⊞ηΣ∨⁺ηEυ§λκ¹

Porta la riga finora e i valori nelle righe precedenti nella colonna corrente e aggiungi il totale della somma alla riga corrente. Tuttavia, se non ci sono valori, sostituisci 1al posto della somma.

⊞υη»

Aggiungi la riga finita all'elenco di righe finora.

I⊟⊟υ

Emette il valore finale calcolato.



2

Pari / GP , 43 byte

Secondo OEIS , la funzione generatrice di questa sequenza è

12(1-X1-9X+1)

n->Vec(sqrt((1-x)/(1-9*x)+O(x^n++))+1)[n]/2

Provalo online!


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.