Подсчет количества ограниченных лесов по лестнице Мебиуса длины n


13

Последовательность OEIS A020872 подсчитывает количество ограниченных лесов на лестнице Мёбиуса M n .

Соревнование

Задача состоит в том, чтобы написать программу, которая принимает целое число в качестве входных данных n > 1и возвращает A020872(n)количество ограниченных лесов по лестнице Мёбиуса M n . Это , поэтому выигрывает самый короткий код. (Скрытый мотив - возможно, немного увеличить длину этой последовательности.)

Определения

Ограниченный лес является разбиением графа таким образом, что каждая часть является либо (неориентированным) путем или изолированная вершина.

Мёбиусово лестница М п представляет собой график , который можно рассматривать в 2n-угольник с диагоналями нарисованных между всеми противоположными вершинами.

пример

Вот 34 ограниченных леса на М 2 (квадрат с нарисованными диагоналями). Обратите внимание, что первый граф разбит на четыре изолированные вершины, второй разбит на один путь и две изолированные вершины и т. Д. A020872 (2)


1
Тестовые случаи от 2 до 12: 34, 241, 1582, 10204, 65197, 415076, 2638366, 16759249, 106427154, 675771276, 4290678337. Я не уверен, почему ввод 1не требуется, с выводом 2.
Питер Тейлор

@PeterTaylor, спасибо за добавление этих терминов в OEIS! Я исключил ввод, 1потому что M_1 четко не определено в статье Википедии. (В частности, он либо имеет несколько ребер, либо не является кубическим графом.)
Питер Кейджи

1
Это на самом деле звучит как хороший кандидат на вызов fastest-codeили fastest-algorithmвызов.
Mypetlion

1
Дальнейшие тестовые случаи ( код генерации ): с 13 по 1727242281044, 172964658642, 1098170541121, 6972388689086, 44268329738124
Питер Тейлор,

1
Да, я думаю, что ваш скрытый мотив более чем удовлетворен.
Питер Тейлор

Ответы:


10

CJam ( 58 56 символов)

Некоторые символы недоступны для печати, и одна из них - это вкладка, которая будет искажена программным обеспечением StackExchange:

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

Демо онлайн . Это будет работать в режиме онлайн при n = 400 примерно через три секунды.

Кодируется 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=

объяснение

Лестница Мёбиуса - это, в основном, лестница с двумя дополнительными ребрами. Учитывая ограниченный лес на лестнице, его можно поднять от 1 до 4 ограниченных лесов на лестнице Мёбиуса. Ребра могут быть добавлены при условии, что они не создают вершину степени 3 или цикл. Степени четырех углов и их взаимосвязи образуют 116 классов ограниченного леса на лестнице, хотя некоторые из них эквивалентны из-за симметрии прямоугольника. Я написал программу для анализа расширений лестниц длины n на длину лестниц n + 1, а затем объединил классы в 26 классов эквивалентности. Это дает закрытую форму

[1111]T[1220121123410010]n2[0100]+

[221111122]T[211111111101001010002010000001010000000100001110000011001000011322112142000100002]n2[002200000]+

[1244113222344]T[0001000000100020010000000001201101101111004003002000000000001021001000000000111001002001000012000010001201001000000000002002001000000000000010000000000102200230110210124]n2[1011201000121]

so values can be computed fast by taking three linear recurrences and then adding them, but this isn't looking very golfy.

However, if we take the irreducible factors of the various characteristic polynomials and multiply together one of each (ignoring multiplicity) we get a polynomial of degree 10 which gives a working single linear recurrence.

Constructive approach (58 chars)

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

Online demo. It will run online for n=2 without problems and for n=3 with a bit of patience. For n=1 it crashes, but since OP has chosen to exclude that case from the requirements it's not a fundamental problem.

Dissection

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

A more efficient version takes 98 bytes:

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

Online demo

This builds the possible paths by depth-first search, then uses a memoised function which counts the possible restricted forests for a given set of vertices. The function works recursively on the basis that any restricted forest for a given non-empty set of vertices consists of a path containing the smallest vertex and a restricted forest covering the vertices not in that path.


On the grid graph, this can be described with a linear recursion, so it wouldn’t surprise me to find out that this is nice.
Peter Kagey

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

Try it online!

Notes:

  • This is quite inefficient and will time-out on TIO for n>4.
  • a(5)=10204 was found in a bit less than 3 minutes on my laptop.

Commented

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

Желе , 61 58 байт

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

Попробуйте онлайн!

Это более короткая версия; он оптимизирован для сокращения длины по сравнению с алгоритмической сложностью и скоростью.

Желе , 85 байт

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

Попробуйте онлайн!

Вот более длинная версия, которая добавляет дополнительный код, чтобы избежать использования избыточных путей. Проверка для n = 2 в конце состоит в том, чтобы справиться с конкретным случаем для n = 2, который в примере выглядит как красно-синий крестик и не генерируется этим кодом. Эта вторая версия завершила n = 4 менее чем за 13 секунд на TIO, но время ожидания для больших чисел.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.