長さnのメビウスの梯子の制限された森林の数を数える


13

OEISシーケンスA020872は、メビウスのはしご M nの制限された森林の数をカウントします。

チャレンジ

課題は、入力として整数を受け取り、メビウスのはしごM nにある制限された森林の数をn > 1返すプログラムを書くことです。これはなので、最短のコードが優先されます。(不純な動機は、おそらくこのシーケンスの長さを少し延長することです。)A020872(n)

定義

制限された森は、各部分が(無向)のいずれかであるようなグラフのパーティションである経路又は単離された頂点。

メビウスのラダー M nはすべて反対の頂点の間に引かれた対角線と2N角形と考えることができるグラフです。

M 2にある34の制限された森林(対角線が描かれた正方形)は次のとおりです。最初のグラフは4つの分離された頂点に分割され、2番目のグラフは1つのパスと2つの分離された頂点に分割されていることに注意してください。 A020872(2)


1
2〜12のテストケース:34, 241, 1582, 10204, 65197, 415076, 2638366, 16759249, 106427154, 675771276, 42906783371outputで入力も必要ない理由はわかりません2
ピーターテイラー

@ PeterTaylor、OEISにこれらの用語を追加していただきありがとうございます!1M_1はウィキペディアの記事で明確に定義されていないため、入力を除外しました。(特に、複数のエッジがあるか、立方グラフではありません。)
ピーターカゲィ

1
これは実際に、fastest-codeまたはfastest-algorithmチャレンジの良い候補のように聞こえます。
-mypetlion

1
さらにテストケース(世代コード):27242281044, 172964658642, 1098170541121, 6972388689086, 44268329738124
ピーターテイラー

1
そうです、あなたの不純な動機は満足以上のものだと思います。
ピーターテイラー

回答:


10

Cジャム(58 56文字)

一部の文字は印刷できません。1つはStackExchangeソフトウェアによってマングルされるタブです。

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

オンラインデモ。これは、約3秒で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=

説明

メビウスのはしごは、基本的に2つの余分なエッジを持つはしごです。はしごに制限された森林がある場合、メビウスのはしごにある1〜4個の制限された森林に持ち上げることができます。次数3の頂点またはサイクルを作成しない限り、エッジを追加できます。4つの角の角度とそれらの相互接続は梯子の116種類の制限された森林を形成しますが、それらのいくつかは長方形の対称性により同等です。長さnのはしごから長さn + 1のラダーへの拡張を分析するプログラムを作成し、クラスを26の等価クラスにマージしました。これは閉じた形を与えます

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

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

[1244113222344]T[0001000000100020010000000001201101101111004003002000000000001021001000000000111001002001000012000010001201001000000000002002001000000000000010000000000102200230110210124]n2[1011201000121]

そのため、3つの線形回帰を取得して追加することで値を高速に計算できますが、これはあまりゴルフっぽくありません。

ただし、さまざまな特性多項式の既約因子を取り、それぞれを乗算すると(多重度は無視されます)、次数10の多項式が得られます。

建設的なアプローチ(58文字)

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

オンラインデモn=2問題なくn=3、少しの忍耐でオンラインで実行されます。以下のためにn=1それにクラッシュが、OPが要件からそのような場合を除外することを選択したので、それは根本的な問題ではありません。

解剖

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

より効率的なバージョンは98バイトかかります:

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

オンラインデモ

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.


グリッドグラフでは、これを線形再帰で記述することができるため、これが素晴らしいことを知って驚かないでしょう。
ピーターカゲィ

6

JavaScript(ES6)、 160 158  146バイト

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

オンラインでお試しください!

ノート:

  • これは非常に非効率的で、TIOでタイムアウトします n>4
  • a5=10204 ラップトップで3分未満で発見されました。

コメント済み

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の特定のケースに対処することです。この2番目のバージョンは、TIOで13秒未満でn = 4を完了しましたが、数値が大きいとタイムアウトします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.