Contando o número de florestas restritas na escada de Möbius de comprimento n


13

A sequência OEIS A020872 conta o número de florestas restritas na escada Möbius M n .

O desafio

O desafio é escrever um programa que use um número inteiro como entrada n > 1e retorne A020872(n)o número de florestas restritas na escada Möbius M n . Isso é , então o código mais curto vence. (Um motivo oculto talvez seja estender um pouco a duração dessa sequência.)

Definições

Uma floresta restrita é uma partição do gráfico, de modo que cada parte seja um caminho (não direcionado) ou um vértice isolado.

A escada Möbius M n é um gráfico que pode ser pensado no 2n-gon com diagonais desenhadas entre todos os vértices opostos.

Exemplo

Estes são os 34 florestas restringido em H 2 (um quadrado com diagonais desenhada). Observe que o primeiro gráfico é particionado em quatro vértices isolados, o segundo é particionado em um caminho e dois vértices isolados, etc. A020872 (2)


1
Os casos de teste de 2 a 12: 34, 241, 1582, 10204, 65197, 415076, 2638366, 16759249, 106427154, 675771276, 4290678337. Não sei por que a entrada 1também não é necessária, com a saída 2.
22619 Peter Peter

@ PeterTaylor, obrigado por adicionar esses termos ao OEIS! 1Excluí a entrada porque M_1 não está claramente definido no artigo da Wikipedia. (Em particular, seja ele tem várias arestas ou não é um gráfico cúbico.)
Pedro Kagey

1
Isso realmente soa como um bom candidato para um fastest-codeou fastest-algorithmdesafio.
mypetlion 26/03/19

1
Casos mais teste ( código de geração ): 13 a 17 são27242281044, 172964658642, 1098170541121, 6972388689086, 44268329738124
Peter Taylor

1
Certo, acho que seu motivo oculto é mais do que satisfeito.
Peter Taylor

Respostas:


10

CJam ( 58 56 caracteres)

Alguns caracteres não podem ser impressos e um é uma guia que será mutilada pelo software StackExchange:

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

Demonstração online . Isso funcionará online por n = 400 em cerca de três segundos.

Codificado por 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=

Explicação

Uma escada Möbius é basicamente uma escada com duas arestas extras. Dada uma floresta restrita em uma escada, ela pode ser elevada para 1 a 4 florestas restritas na escada Möbius. As arestas podem ser adicionadas desde que não crie um vértice de grau 3 ou um ciclo. Os graus dos quatro cantos e suas interconexões formam 116 classes de floresta restrita na escada, embora algumas sejam equivalentes devido às simetrias do retângulo. Escrevi um programa para analisar as extensões de uma escada de comprimento n para uma de comprimento n + 1 e depois mesclei as classes em 26 classes de equivalência. Isso dá uma forma fechada

[1111]T[1220 0121123410 00 010 0]n-2[0 010 00 0]+

[221111122]T[21111111110 010 00 010 010 00 00 020 010 00 00 00 00 00 010 010 00 00 00 00 00 00 010 00 00 00 01110 00 00 00 00 0110 00 010 00 00 00 0113221121420 00 00 010 00 00 00 02]n-2[0 00 0220 00 00 00 00 0]+

[1244113222344]T[0 00 00 010 00 00 00 00 00 010 00 00 020 00 010 00 00 00 00 00 00 00 00 0120 0110 0110 011110 00 040 00 030 00 020 00 00 00 00 00 00 00 00 00 00 010 0210 00 010 00 00 00 00 00 00 00 00 01110 00 010 00 020 00 010 00 00 00 0120 00 00 00 010 00 00 0120 010 00 010 00 00 00 00 00 00 00 00 00 00 020 00 020 00 010 00 00 00 00 00 00 00 00 00 00 00 00 010 00 00 00 00 00 00 00 00 00 010 0220 00 0230 0110 0210 0124]n-2[10 01120 010 00 00 0121]

para que os valores possam ser calculados rapidamente, usando três recorrências lineares e adicionando-as, mas isso não parece muito complicado.

No entanto, se pegarmos os fatores irredutíveis dos vários polinômios característicos e multiplicarmos um de cada um (ignorando a multiplicidade), obteremos um polinômio de grau 10 que fornece uma recorrência linear única e funcional.

Abordagem construtiva (58 caracteres)

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

Demonstração online . Ele funcionará on-line n=2sem problemas e n=3com um pouco de paciência. Para n=1ele trava, mas desde OP escolheu para excluir esse caso das exigências não é um problema fundamental.

Dissecação

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

Uma versão mais eficiente leva 98 bytes:

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

Demonstração online

Isso cria os caminhos possíveis por meio da pesquisa aprofundada e, em seguida, usa uma função memorizada que conta as possíveis florestas restritas para um determinado conjunto de vértices. A função funciona recursivamente com base em que qualquer floresta restrita para um determinado conjunto de vértices não vazios consiste em um caminho que contém o menor vértice e uma floresta restrita que cobre os vértices que não estão nesse caminho.


No gráfico de grade, isso pode ser descrito com uma recursão linear; portanto, não me surpreenderia descobrir que isso é bom.
Peter Kagey 28/03/19

6

JavaScript (ES6),  160 158  146 bytes

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)))``

Experimente online!

Notas:

  • Isso é bastante ineficiente e irá expirar no TIO para n>4.
  • uma(5)=10204 foi encontrado em pouco menos de 3 minutos no meu laptop.

Comentado

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

Geléia , 61 58 bytes

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

Experimente online!

Esta é a versão mais curta; é otimizado para menor comprimento versus complexidade e velocidade algorítmica.

Geléia , 85 bytes

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

Experimente online!

Aqui está uma versão mais longa que adiciona código extra para evitar tentativas de caminhos redundantes. A verificação de n = 2 no final é para lidar com o caso específico de n = 2, que se parece com uma cruz vermelha / azul no exemplo e não é gerado por esse código. Esta segunda versão completou n = 4 em menos de 13 segundos no TIO, mas atinge o tempo limite para números mais altos.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.