トーラス上のサイクル


20

チャレンジ

この課題は、次の2つの整数を取り込んでプログラム書く必要がありますnし、mそして上の番号非交差ループを出力nすることによってmで起動することによって作られたトーラス(0,0)とステップのみを取って右へを。トーラスは、上部と下部、側面の両方にラップアラウンドしたグリッドと考えることができます。

これはので、バイト数が最も少なくなります。

たとえば、入力がの場合n=m=5、1つの有効なウォークは

(0,0) -> (0,1) -> (0,2) -> (1,2) -> (2,2) -> (2,3) -> (2,4) -> 
(2,0) -> (3,0) -> (4,0) -> (4,1) -> (4,2) -> (4,3) -> 
(0,3) -> (1,3) -> (1,4) -> 
(1,0) -> (1,1) -> (2,1) -> (3,1) -> (3,2) -> (3,3) -> (3,4) -> (4,4) -> 
(0,4) -> (0,0)

図に示すように。

トーラスのループ。

いくつかの例の入力/出力

f(1,1) = 2 (up or right)
f(1,2) = 2 (up or right-right)
f(2,2) = 4 (up-up, up-right-up-right, right-right, right-up-right-up)
f(2,3) = 7
f(3,3) = 22
f(2,4) = 13
f(3,4) = 66
f(4,4) = 258

1
私はこのシーケンスが少なくとも OEISにあったことを賭けたいと思っていましたが、明らかに(まだ)そうではありません。m=n
アーナウルド

トーラスには左右のラップアラウンドもあると思います。代わりにアップダウンラップアラウンドのみを想定する必要がありますか?サンプル画像は、そのようなことを暗示していないようです。
アウトゴルファーのエリック

@EriktheOutgolfer画像には、右から左にオレンジ色のパスが回り込んでいますよね?
アーナルド

@Arnauldはい。ただし、チャレンジの説明と一致していないようです(「トーラスは、上部と下部の両方にラップアラウンドを備えたグリッドと考えることができます。」)
Erik the Outgolfer

@EriktheOutgolferそれは本当です。そして今あなたがそれについて言及したので、青い道は間違っています。最初に右から左へ、次に上から下へラップアラウンドする必要があります。
アーナルド

回答:


4

ゼリー、28 バイト

ạƝ§=1Ȧ
²‘p/’ŒPÇƇḢÐṂ%⁸QƑƇṪÐṂL

[m,n]カウントを生成するリストを受け入れる単項リンク。

TIO-jt1qe1v9 ...ほとんど意味はありませんが、あまりにも非効率的です。
[2,3]16GB RAMでローカルに実行することさえできません)!

どうやって?

ブルートフォース-タイル化されたバージョンの座標を十分に大きくし、これらのポイントのパワーセットを、単一方向に1だけ増加する近傍のパスにフィルターし、最小座標(つまり、原点)で開始するパスにフィルターします。同時に、それぞれからこの開始座標を削除します。次に、モジュロ演算を使用してトーラスにラップバックし、重複する座標(交差点を含む座標)をフィルタリングし、最後に、終了座標が最小の座標(原点で終了する座標)をフィルタリングし、結果の長さを返します。

ạƝ§=1Ȧ - Link 1: all neighbours differ by 1 in exactly one direction
 Ɲ     - for neighbours:
ạ      -   absolute difference
  §    - sum each
   =1  - equal to one (vectorises)
     Ȧ - any and all? (falsey if empty or contains a falsey value when flattened)

²‘p/’ŒPÇƇḢÐṂ%⁸QƑƇṪÐṂL - Main Link: list of integers, [m,n]
²                     - square (vectorises) -> [m*m, n*n]
 ‘                    - increment (vectorises) -> [m*m+1, n*n+1]
   /                  - reduce with:
  p                   -   Cartesian product
    ’                 - decrement (vectorises) -> all the coordinates of an m*m by n*n grid
                      -                           including [0, 0] and [m*m, n*n] 
     ŒP               - power-set -> all paths going either up OR right at each step, but not
                      -              necessarily by only 1, and
                      -              necessarily both up and right (e.g. [...[1,3],[5,7],[6,2],...])
        Ƈ             - filter keep those for which:
       Ç              -   call last Link (1) as a monad
                      -              ...now all remaining paths do only go in steps
                      -              of one up or one right
          ÐṂ          - filter keep those minimal under:
         Ḣ            -   head - removes the 1st coordinate from each and yields them for the filter
                      -          ...so only those which started at [0,0] but without it
            %⁸        - modulo by the left argument ([m,n]) (vectorises)
                Ƈ     - filter keep those for which:
               Ƒ      -   is invariant when:
              Q       -     de-duplicated
                      -          ...so no repetitions of torus coordinates (and we already removed
                      -          the first [0,0] which must be present exactly twice)
                  ÐṂ  - filter keep those minimal under:
                 Ṫ    -   tail
                      -          ...so only those which ended at [0,0] 
                    L - length

12

Python 2、87バイト

f=lambda m,n,z=0,l=[]:z==0if z in l else sum(f(m,n,(z+d)%m%(n*1j),l+[z])for d in(1,1j))

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

ここで興味深いのは、複素数を使用しzて現在の位置の座標を保存することです。を追加して上に移動し、を追加1して右に移動でき1jます。驚いたことに、モジュロは、各次元のラッピングを個別に処理できるように複素数を処理します。%m実部での%(n*1j)動作と虚部での動作を行います。


よくできました。FWIW、複素数を使用しない私の最善の試みは、Python 3.8で91バイトです。
アーナウルド

@Arnauldの興味深いアイデアk:=x+y*m。それを使用kするので(x,y)x+y*mなく、直接使用する方が短いのではないかと思うx+y*1j。残念なことに、Python 3は複素モジュラスを許可していません。
9:59の


このアプローチは、JSで5バイトを節約します。:)
アーナウド

7

JavaScript(ES6)、67バイト

この短いバージョンは、@ xnorによって検出されたPython 3.8の代替バージョンから派生しています。ただし、これはのみ機能しますm×n<32はJSます。

入力をとして受け取ります(m)(n)

m=>n=>(g=(k,l)=>l>>k&1?!k:g((k+m)%(m*n),l|=1<<k)+g(k-~k%m-k%m,l))``

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

任意の入力で動作させるには、73バイトの BigIntsを使用できます

m=>n=>(g=(k,l=k)=>l&(b=1n<<k)?!k:g((k+m)%(m*n),l|=b)+g(k-~k%m-k%m,l))(0n)

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


JavaScript(ES6)、 76 73  72バイト

入力をとして受け取ります(m)(n)

m=>n=>(g=(x,y)=>g[x+=y*m]?!x:g(-~x%m,y,g[x]=1)+g(x%m,-~y%n)+--g[x])(0,0)

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

コメント済み

m => n => (         // m = width; n = height
  g = (             // g is a recursive function taking:
        x, y        //   the current coordinates (x, y) on the torus
      ) =>          //
    g[              // the surrounding object of g is also used for storage
      x += y * m    // turn x into a key for the current coordinates
    ] ?             // if this cell was already visited:
      !x            //   return 1 if we're back to (0, 0), or 0 otherwise
    :               // else:
      g(            //   first recursive call:
        -~x % m,    //     move to the right
        y,          //     leave y unchanged
        g[x] = 1    //     mark the current cell as visited by setting the flag g[x]
      ) +           //   add the result of
      g(            //   a second recursive call:
        x % m,      //     restore x in [0...m-1]
        -~y % n     //     move up
      ) +           //
      --g[x]        //   clear the flag on the current cell
)(0, 0)             // initial call to g with (x, y) = (0, 0)

3

Haskell、88 80バイト

n#m|let(x!y)a|elem(x,y)a=0^(x+y)|b<-(x,y):a=(mod(x+1)n!y)b+(x!mod(y+1)m)b=0!0$[]

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

単純なブルートフォース:すべての上下の組み合わせを試し、交差するものをドロップします(訪問したすべての位置をリストに保持します) a)、最終的にポジショニングにヒットするものをカウント(0,0)します。

再帰の基本的なケースは、2回目にポジションを訪れたときです(elem(x,y)a)。結果は、0^0= 1位置が(0,0)ループの数にカウントされるとき、または00^xxゼロ以外の値で)それ以外の場合、ループの数は増加しません。

編集:@xnorのおかげで-8バイト。


1
ベースケースはに結合でき|elem(x,y)a=0^(x+y)(0!0)[]することができます0!0$[]
XNOR



1

CJam(50文字)

q~]:M:!a{9Yb2/\f{_W=@.+M.%a+_)a#g"WAR"=~}}:R~e_We=

オンラインデモ。これは、stdinから2つの入力を受け取るプログラムです。

最後に、質問に対する答えがあります

戦争、ハァッ、それは何のために良いですか?


解剖

q~]:M        e# Parse input, collect in array, store in M (for moduli)
:!a          e# Zero and wrap in array for starting position (0, 0)
{            e# Define recursive block R
  9Yb2/      e#   Push [[1 0][0 1]], an array of movements
  \f{        e#   For each of those movements, with the current path,
    _W=@.+   e#     Add the movement to the last position in the path
    M.%      e#     Apply the wrapping
    a+       e#     Add to one copy of the path
    _)a#     e#     And find its index in another copy
    g"WAR"=~ e#     Switch on the sign of the index:
             e#       If the sign is -1, position not found, make a recursive call
             e#       If the sign is 0, found at start, push -1 to the stack
             e#       If the sign is 1, we have a self-intersection. We push 10 to
             e#       the stack for no other reason than to make the bad joke above
  }
}:R
~            e# Execute R
e_We=        e# Count the -1s which we pushed as sentinels

1

ゼリー54 39バイト

ḣ2æ.2ị³¤+4
‘Ç;¥¦%³Ç=4ƊÑÇị$?
çⱮؽS
’Ñ0xÇ

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

これは完全に異なる方法であるため、これを他のJellyの別の回答として投稿しました。これは、原則として@Arnauldの答えに近いものです。再帰的な関数を使用して、すべての可能なパスを介して、既に到達しているポイントに到達するまで動作し、最初に戻ったかどうかのチェック結果を返します。あと数バイト削り取れると思う。スライス演算子の使用に変更されました。5x5まで対応しています。再帰の深さは最大でmx nでなければなりません。

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