Conteggio di polistrip


18

I polistrip sono un sottoinsieme di poliomino conformi alle seguenti regole:

  • ogni pezzo è composto da 1 o più celle
  • nessuna cellula può avere più di due vicini
  • le celle non dovrebbero racchiudere un buco

I poliomino liberi sono distinti quando nessuno è una trasformazione rigida (traslazione, rotazione, riflessione o riflessione di planata) di un altro (pezzi che possono essere raccolti e capovolti). Tradurre, ruotare, riflettere o scivolare riflettendo un poliamino libero non cambia forma ( Wikipedia )

Ad esempio, ci sono 30 heptastrips gratuiti (polystrips con lunghezza 7). Eccoli tutti, confezionati in una griglia 14x15.

Heptastrips

Credito d'immagine: Miroslav Vicher

Obbiettivo

Scrivi un programma / funzione che accetta un intero positivo ncome input ed enumera le distinte n-polystrips distinte .

  • n = 1 -> 1 (un singolo quadrato)

  • n = 2 -> 1 (Esiste solo una possibile 2 polistrip composta da 2 quadrati)

  • n = 3 -> 2 (uno è composto da 3 quadrati uniti in una linea e l'altro a forma di L)

  • n = 4 -> 3 (uno dritto, uno a L e uno a Z)

  • . . .

Casi test:

n   polystrips

1   1
2   1
3   2
4   3
5   7
6   13
7   30
8   64
9   150
10  338
11  794
12  1836
13  4313
14  10067
15  23621

punteggio

Questo è , quindi il codice più corto è migliore. Apprezzerei molto le spiegazioni dettagliate dell'algoritmo e del codice.

Implementazione parziale di riferimento in J

Ho deciso di descrivere ogni pezzo in formato "vettoriale" e ho solo bisogno di blocchi n-2 per descrivere un pezzo n-polystrip (c'è solo 1 polistrip 2 ed è restituito esplicitamente). I blocchi descrivono la direzione relativa: 0 - nessuna modifica; 1 - svolta a sinistra; 2 - girare a destra. Non importa quale direzione si inizierà, ma solo per indicare dove deve essere posizionata la cella successiva. Può esserci un numero qualsiasi di 0 consecutivi, ma 1 e 2 sono sempre singoli. Questa implementazione è parziale, perché non tiene conto dei fori - le soluzioni per n> 6 contano anche i pezzi con fori.

Provalo online!


1
OEIS pertinente. (Ma non esclude i buchi.)
Martin Ender,

@ Martin Ender Grazie, non lo sapevo.
Galen Ivanov,

2
Giusto per essere sicuro, suppongo che se si riempie una griglia 3x3 ad eccezione del centro e di un angolo che conta anche come un buco ( 101010nella notazione del campione)?
Ton Hospel,

@Ton Hospel Sì, esattamente - questo è l'unico pezzo di heptastrip con un foro.
Galen Ivanov,

1
Forse una buona domanda per math.SE
Giona

Risposte:


12

Python 3 , 480 433 406 364 309 299 295 byte

Sembrava un buon punto per iniziare la mia carriera in PPCG (o no?).

def C(s):
 S,*a={''},0,1;n=d=r=1
 for c in s:d=c*d*1jor d;n+=d;a+=n,;r*=not{n}&S;x,*a=a;S|={x+t+u*1jfor t in A for u in A}
 return r
from itertools import*;A=-1,0,1;n,y=int(input())-2,0;x={*filter(C,product(*[A]*n))}
while x:s=x.pop();S=*(-u for u in s),;x-={s[::-1],S,S[::-1]}-{s};y+=1
print(y)

Provalo online!

modifiche:

  • Inline De X, e leggermente modificato, in alcuni punti del golf.
  • Ha applicato più trucchi, principalmente quelli relativi al set.
  • Modificato nel modulo del programma e modificato in numeri complessi anziché in numeri arbitrari m. (I numeri complessi sono davvero una caratteristica da golf forte ma spesso ignorata; adattato dalla soluzione di xnor per un'altra sfida )
  • Modificata la LFRrappresentazione in stringhe in -1,0,1tuple e sacrificato il tempo di esecuzione per una quantità folle di riduzione dei byte (!). Ora la soluzione è teoricamente corretta ma i timeout prima di produrre il risultato per 15.
  • Ho completato il ciclo grazie a Jonathan Frech, quindi ho trovato l'alternativa molto migliore per il calcolo r. FINALMENTE SOTTO I 300 BYTES !!!
  • Sorprendentemente 1jpuò attenersi a qualsiasi altra cosa senza confondere il parser (-2B) e notha una follemente bassa precedenza (-2B).

Versione obsoleta (480 byte):

def C(s):
 m=999;a=[0,1];n=d=1
 D={'F':{},'L':{1:m,m:-1,-1:-m,-m:1},'R':{1:-m,-m:-1,-1:m,m:1}}
 X=lambda x:{x+~m,x-m,x-m+1,x-1,x,x+1,x+m-1,x+m,x-~m}
 for c in s:
  d=D[c].get(d,d);n+=d;a+=n,
  if n in set().union(*map(X,a[:-3])):return 0
 return 1
def f(n):
 if n<3:return 1
 x={*'LF'}
 for _ in range(3,n):x={s+c for s in x for c in({*'LRF'}-{s[-1]})|{'F'}}
 y={*x}
 for s in x:
  if s in y:S=s.translate(str.maketrans('LR','RL'));y-={s[::-1],S,S[::-1]}-{s}
 return sum(map(C,y))

Provalo online!

Soluzione non golfata con commenti:

t = str.maketrans('LR','RL')

# hole checking function
def check(s):
    m = 999   # (imaginary) board size enough to fit all generated polyominoes
    a = [0,1] # previous path
    n = 1     # current cell
    d = 1     # current direction
    # dict for direction change
    D = {'F':{}, 'L':{1:m, m:-1, -1:-m, -m:1}, 'R':{1:-m, -m:-1, -1:m, m:1}}
    # used to 'blur' all cells in path into 3x3
    X = lambda x: {x-m-1,x-m,x-m+1,x-1,x,x+1,x+m-1,x+m,x+m+1}
    for c in s:
        d = D[c].get(d,d) # change direction
        n += d            # move current cell
        # the polyomino has a hole if the current cell touches previous cells (including diagonally; thus the blurring function)
        if n in set().union(*map(X,a[:-2])): return False
        a.append(n)       # add current cell to the path
    return True

# main function
def f(n):
    if n < 3: return 1
    x = {*'LF'}
    # generate all polystrips using the notation similar to the reference
    for _ in range(3, n): x = {s+c for s in x for c in ({*'LRF'}-{s[-1]})|{'F'}}
    y = {*x}
    # remove duplicates (mirror, head-to-tail, mirror of head-to-tail) but retain self
    for s in x:
        if s in y:
            S = s.translate(t)
            y -= {s[::-1], S, S[::-1]} - {s}
    # finally filter out holey ones
    return sum(map(check,y))

Provalo online!

m = 999viene scelto perché richiede tempo esponenziale per contare tutto e ci vogliono già circa 8 secondi per calcolare n = 1..15. Forse va bene salvare 1 byte usando 99 invece. Non ne abbiamo più bisogno, e ora è garantito che sia corretto per dimensioni di input arbitrarie, grazie al numero complesso integrato.


5
Benvenuti in PPCG! Sicuramente un modo impressionante per iniziare la tua carriera in PPCG. :)
Martin Ender,

3
Benvenuti in PPCG e grazie per questa soluzione! Avevo già smesso di aspettarmi una soluzione :)
Galen Ivanov,

3
Sembrava un buon punto per iniziare la mia carriera in PPCG (o no?) . Bene, questa è una soluzione sorprendentemente breve a questo la maggior parte di noi non penserebbe nemmeno che potrebbe mai essere, anche la versione non golfata sembra sorprendentemente semplice, ma, eh, forse questo è un modo medio per iniziare la tua carriera in PPCG, giusto? :)
Erik the Outgolfer,

1
@Erik Quella battuta era una mezza battuta :) Ma sì, la soluzione è persino sorprendente per me - non mi sarei mai aspettato di ottenere una riduzione del 36% dall'invio originale.
Gorgogliatore


4

APL (Dyalog Unicode) , 70 65 byte

+/{∧/2≤|(⊢-¯3↓¨,\)+\0 1\0j1*⍵}¨∪{(⊃∘⍋⊃⊢)(⊢,⌽¨)⍵(-⍵)}¨2-,⍳2↓⎕⍴3

Provalo online!

Versione completa del programma del codice seguente, grazie ad Adám.


APL (Dyalog Unicode) , 70 byte

{+/{∧/2≤|(⊢-¯3↓¨,\)+\0 1\0j1*⍵}¨∪{(⊃∘⍋⊃⊢)(⊢,⌽¨)⍵(-⍵)}¨2-,⍳3⍴⍨0⌈⍵-2}

Provalo online!

Come funziona

Il codice sopra è equivalente alla seguente definizione:

gen←{2-,⍳3⍴⍨0⌈⍵-2}
canonicalize←{(⊃∘⍋⊃⊢)(⊢,⌽¨)⍵(-⍵)}
test←{(∧/⊢{∧/2≤|⍺-¯3↓⍵}¨,\)+\0 1\0j1*⍵}
{+/test¨∪canonicalize¨gen⍵}

Funziona come la soluzione Python, ma in un ordine diverso. Si generates LFR-strips di lunghezza n-2, canonicalizes ogni striscia prende strisce nique, tests ciascuna striscia se si tocca (1 se non contigue, 0 altrimenti), e somma +/il risultato booleano.

gen

{2-,⍳3⍴⍨0⌈⍵-2}
{            }   ⍵←input number n
        0⌈⍵-2    xmax(0, n-2)
     3⍴⍨         x copies of 3
   ,⍳            multi-dimensional indexes; x-th cartesian power of [1,2,3]
                 (`⍳` gives x-dimensional hypercube; `,` flattens it)
 2-              compute 2-k for each k in the array

 in each strip, ¯1, 0, 1 corresponds to R, F, L respectively

canonicalize

{(⊃∘⍋⊃⊢)(⊢,⌽¨)⍵(-⍵)}
{                  }   ⍵←single strip
              ⍵(-⍵)    nested array of  and its LR-flip
        (⊢,⌽¨)         concatenate their head-to-tail flips to the above
 (⊃∘⍋  )               find the index of the lexicographically smallest item
     ⊃⊢                take that item

test

{(∧/⊢{∧/2≤|⍺-¯3↓⍵}¨,\)+\0 1\0j1*⍵}
{                                  }   ⍵←single strip
                              0j1*⍵    power of i; direction changes
                            ×\         cumulative product; directions
                        0 1,     initial position(0) and direction(1)
                      +\         cumulative sum; tile locations
 (  ⊢{           }¨,\)    test with current tile(⍺) and all tiles up to ⍺(⍵):
             ¯3↓⍵         x←⍵ with last 3 tiles removed
           ⍺-             relative position of each tile of x from 
        2≤|               test if each tile of x is at least 2 units away
      ∧/                  all(...for each tile in x)
  ∧/         all(...for each position in the strip)

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.