Contando il numero di foreste limitate sulla scala Möbius di lunghezza n


13

La sequenza OEIS A020872 conta il numero di foreste soggette a restrizioni sulla scala Möbius M n .

La sfida

La sfida è scrivere un programma che accetta un numero intero come input n > 1e restituisce A020872(n)il numero di foreste riservate sulla scala Möbius M n . Questo è , quindi vince il codice più corto. (Un ulteriore motivo è forse quello di estendere la lunghezza di questa sequenza di un po '.)

definizioni

Una foresta con restrizioni è una partizione del grafico in modo tale che ogni parte sia un percorso (non indirizzato) o un vertice isolato.

La scala Möbius M n è un grafico che si può pensare alla 2n-gon con diagonali disegnate tra tutti i vertici opposti.

Esempio

Ecco le 34 foreste limitate su M 2 (un quadrato con le diagonali disegnate). Si noti che il primo grafico è partizionato in quattro vertici isolati, il secondo è partizionato in un percorso e due vertici isolati, ecc. A020872 (2)


1
Casi di test da 2 a 12: 34, 241, 1582, 10204, 65197, 415076, 2638366, 16759249, 106427154, 675771276, 4290678337. Non sono sicuro del motivo per cui 1non è richiesto anche l' input , con l'output 2.
Peter Taylor,

@PeterTaylor, grazie per aver aggiunto quei termini a OEIS! Ho escluso l'input 1perché M_1 non è chiaramente definito nell'articolo di Wikipedia. (In particolare, o ha più spigoli o non è un grafico cubico.)
Peter Kagey,

1
Questo in realtà sembra un buon candidato per una fastest-codeo una fastest-algorithmsfida.
mypetlion il

1
Ulteriori casi di test ( codice di generazione ): 13-17 sono27242281044, 172964658642, 1098170541121, 6972388689086, 44268329738124
Peter Taylor

1
Bene, penso che il tuo ulteriore motivo sia più che soddisfatto.
Peter Taylor,

Risposte:


10

CJam ( 58 56 caratteri)

Alcuni caratteri non stampabili, e uno è una scheda che sarà alterata dal software StackExchange:

"¶3¬î¿Á·    7ÛÈmÈÚÚ¡"256b454b212f-{__W%.*A<1b+}qi*-4=

Demo online . Questo funzionerà online per n = 400 in circa tre secondi.

Codificato da xxd:

0000000: 22b6 0233 93ac eebf c1b7 0609 3794 dbc8  "..3........7...
0000010: 6dc8 1015 dada a122 3235 3662 3435 3462  m......"256b454b
0000020: 3231 3266 2d7b 5f5f 5725 2e2a 413c 3162  212f-{__W%.*A<1b
0000030: 2b7d 7169 2a2d 343d                      +}qi*-4=

Spiegazione

Una scala Möbius è fondamentalmente una scala con due bordi extra. Data una foresta limitata su una scala, può essere sollevata tra 1 e 4 foreste limitate sulla scala Möbius. I bordi possono essere aggiunti a condizione che non crei un vertice di grado 3 o un ciclo. I gradi dei quattro angoli e le loro interconnessioni formano 116 classi di foresta ristretta sulla scala, sebbene alcuni di essi siano equivalenti a causa di simmetrie del rettangolo. Ho scritto un programma per analizzare le estensioni di una scala di lunghezza n a una di lunghezza n + 1, quindi ho unito le classi in 26 classi di equivalenza. Questo dà una forma chiusa

[1111]T[1220121123410010]n-2[0100]+

[221111122]T[211111111101001010002010000001010000000100001110000011001000011322112142000100002]n-2[002200000]+

[1244113222344]T[0001000000100020010000000001201101101111004003002000000000001021001000000000111001002001000012000010001201001000000000002002001000000000000010000000000102200230110210124]n-2[1011201000121]

quindi i valori possono essere calcolati rapidamente prendendo tre ricorrenze lineari e quindi aggiungendole, ma questo non sembra molto golfy.

Tuttavia, se prendiamo i fattori irriducibili dei vari polinomi caratteristici e moltiplichiamo insieme uno di ciascuno (ignorando la molteplicità) otteniamo un polinomio di grado 10 che dà una ricorrenza lineare singola funzionante.

Approccio costruttivo (58 caratteri)

qi:Q2*,Wa*e!{Wa/{_W%e<}%$}%_&{{,1>},2few:~{:-z(Q(%}%0-!},,

Demo online . Funzionerà online n=2senza problemi e n=3con un po 'di pazienza. Perché n=1si blocca, ma poiché OP ha scelto di escludere quel caso dai requisiti non è un problema fondamentale.

Dissezione

qi:Q          e# Take input from stdin, parse to int, store in Q
2*,Wa*e!      e# Take all permutations of (0, -1, 1, -1, 2, -1, ..., -1, 2*Q-1)
{             e# Map to canonical form...
  Wa/         e#   Split around the -1s
  {_W%e<}%    e#   Reverse paths where necessary to get a canonical form
  $           e#   Sort paths
}%
_&            e# Filter to distinct path sets
{             e# Filter to path sets with valid paths:
  {,1>},      e#   Ignore paths with fewer than two elements (can't be invalid; break 2ew)
  2few:~      e#   Break paths into their edges
  {:-z(Q(%}%  e#   The difference between the endpoints of an edge should be +/-1 or Q (mod 2Q)
              e#   So their absolute values should be 1, Q, 2Q-1.
              e#   d => (abs(d)-1) % (Q-1) maps those differences, and no other possible ones, to 0
              e#   NB {:-zQ(%}% to map them all to 1 would save a byte, but wouldn't work for Q=2
  0-!         e#   Test that all values obtained are 0
},
,             e# Count the filtered distinct path sets

Una versione più efficiente richiede 98 byte:

qi2*:Q{a{__0=[1Q2/Q(]f+Qf%_&1$-\f{+E}~}:E~}/]{_W%>!},:MW=0{_{M\f{__3$_@&@:e<@|^{=}{^j}?}1b}{,)}?}j

Demo online

Questo crea i possibili percorsi mediante una ricerca approfondita, quindi utilizza una funzione memorizzata che conta le possibili foreste limitate per un determinato insieme di vertici. La funzione funziona in modo ricorsivo sulla base del fatto che qualsiasi foresta limitata per un dato insieme di vertici non vuoto è costituita da un percorso contenente il vertice più piccolo e una foresta limitata che copre i vertici non in quel percorso.


Sul grafico a griglia, questo può essere descritto con una ricorsione lineare, quindi non mi sorprenderebbe scoprire che è bello.
Peter Kagey,

6

JavaScript (ES6),  160 158  146 byte

n=>(g=(e,v,p)=>[...Array(N=2*n),N-1,1,n].reduce((s,x,i)=>(m=1<<(x=i<N?i:(p+x)%N))&v?s:s+g((i>=N)/p?[...e,1<<p|m]:e,v|m,x),g[e.sort()]^(g[e]=1)))``

Provalo online!

Appunti:

  • Questo è abbastanza inefficiente e scadrà su TIO per n>4.
  • un'(5)=10204 è stato trovato in poco meno di 3 minuti sul mio laptop.

Commentate

n => (                        // n = input
  g = (                       // g = recursive function taking:
    e,                        //   e[] = array holding visited edges
    v,                        //   v   = bitmask holding visited vertices
    p                         //   p   = previous vertex
  ) =>                        // we iterate over an array of N + 3 entries, where N = 2n:
    [ ...Array(N = 2 * n),    //   - 0...N-1: each vertex of the N-gon (starting points)
      N - 1,                  //   - N      : previous vertex \
      1,                      //   - N+1    : next vertex      }-- connected to p
      n                       //   - N+2    : opposite vertex /
    ].reduce((s, x, i) =>     // reduce() loop with s = accumulator, x = vertex, i = index:
      ( m = 1 << (            //   m is a bitmask where only the x-th bit is set
          x = i < N           //   and x is either:
              ? i             //   - i if i < N
              : (p + x) % N   //   - or (p + x) mod N otherwise
      )) & v ?                //   if this vertex was already visited:
        s                     //     leave s unchanged
      :                       //   else:
        s +                   //     add to s
        g(                    //     the result of a recursive call:
          (i >= N) / p ?      //       if p and x are connected (i >= N and p is defined):
            [ ...e,           //         append to e[]:
              1 << p | m      //           the edge formed by p and x
            ]                 //           and uniquely identified by 1 << p | 1 << x
          :                   //       else:
            e,                //         leave e[] unchanged
          v | m,              //       mark the vertex x as visited
          x                   //       previous vertex = x
        ),                    //     end of recursive call
      g[e.sort()] ^           //   sort the edges and yield 1 if this list of edges has not
      (g[e] = 1)              //   already been encountered; either way, save it in g
    )                         // end of reduce()
)``                           // initial call to g with e = ['']

2

Gelatina , 61 58 byte

®R,³;Ø+
Ḥ©Ḷµ1ị+¢%®ḟ€;€€1¦-Ẏ;€)Ẏ$ƬẎṣ€-Ẉ’ẠƊƇU¹Ø.ị>/Ɗ?€€Ṣ€QL‘

Provalo online!

Questa è la versione più breve; è ottimizzato per una lunghezza inferiore rispetto a complessità e velocità algoritmiche.

Gelatina , 85 byte

%®ḟ
1ị+³;Ø+¤ç,1ị+®_3¤R‘¤Ʋç;€-Ʋ“”2ị>-Ʋ?Ẏ;€
Ḥ©Ḷ;€-Ç€Ẏ$ƬẎṣ€-Ẉ=1ẸƊÐḟU¹1ị>0ị$Ʋ?€€Ṣ€QL‘+=2$

Provalo online!

Ecco una versione più lunga che aggiunge ulteriore codice per evitare di provare percorsi ridondanti. Il controllo per n = 2 alla fine è quello di far fronte al caso specifico di n = 2 che nell'esempio appare come una croce rossa / blu e non è generato da questo codice. Questa seconda versione ha completato n = 4 in meno di 13 secondi su TIO, ma scade per numeri più alti.

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.