Zyklen auf dem Torus

20

Herausforderung

Diese Herausforderung haben Sie ein Programm schreiben, das in zwei ganzen Zahlen nimmt nund mdie Anzahl nicht-schneidenden Schleifen auf dem und gibt ndurch mTorus hergestellt durch ab (0,0)und nur Schritte unternommen und nach rechts. Sie können sich Torus als Gitter vorstellen, das oben, unten und an den Seiten umlaufend angeordnet ist .

Dies ist so dass die wenigsten Bytes gewinnen.

Beispiel

Wenn zum Beispiel die Eingabe ist n=m=5, ist ein gültiger Spaziergang

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

wie in der Grafik gezeigt.

Eine Schleife am Torus.

Einige Beispiele für Ein- / Ausgänge

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
Peter Kagey
quelle
1
Ich war bereit zu wetten, dass diese Sequenz für mindestens auf OEIS war , aber anscheinend ist es (noch) nicht. m=n
Arnauld
Ich denke, ein Torus hat auch einen Umlauf von links nach rechts. Sollen wir davon ausgehen, dass es stattdessen nur einen Umlauf nach oben und unten gibt? Das Beispielbild scheint nicht als solches zu gelten.
Erik der Outgolfer
@EriktheOutgolfer Das Bild zeigt den orangefarbenen Pfad von rechts nach links, nicht wahr?
Arnauld
@Arnauld Ja, aber es scheint nicht mit der Beschreibung der Herausforderung übereinzustimmen ("Sie können sich Torus als das Gitter mit Umlauf oben und unten
vorstellen
@EriktheOutgolfer Das stimmt. Und jetzt, wo Sie es erwähnen, ist der blaue Weg falsch. Es sollte zuerst von rechts nach links und dann von oben nach unten umlaufen.
Arnauld

Antworten:

4

Gelee , 28 Bytes

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

Ein monadischer Link, der eine Liste akzeptiert [m,n], die die Anzahl angibt.

TIO-jt1qe1v9 ... obwohl es wenig Sinn macht, ist es viel zu ineffizient.
(Ich kann nicht einmal[2,3]lokal mit 16 GB RAMlaufen)!

Wie?

Brute Force - Erstellt Koordinaten einer gekachelten Version, die groß genug sind, und filtert dann die Potenz dieser Punkte zu den Pfaden, bei denen die Nachbarn nur um eins in einer Richtung zunehmen. Filtert dann zu den Pfaden, die bei einer minimalen Koordinate (dh dem Ursprung) beginnen. Entfernt gleichzeitig diese Startkoordinate von jeder. Verwenden Sie dann die Modulo-Arithmetik, um in einen Torus zurückzukehren, und filtern Sie alle doppelten Koordinaten heraus (dh diejenigen, die Schnittpunkte enthalten) und filtern Sie schließlich nach solchen mit minimalen Endkoordinaten (dh mit dem Ursprung zurück), um die Länge des Ergebnisses zu erhalten.

ạƝ§=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
Jonathan Allan
quelle
12

Python 2 , 87 Bytes

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

Probieren Sie es online!

Das Interessante dabei ist die Verwendung einer komplexen Zahl zzum Speichern der Koordinate der aktuellen Position. Wir können durch Hinzufügen nach oben und durch Hinzufügen 1nach rechts gehen 1j. Zu meiner Überraschung arbeitet modulo mit komplexen Zahlen so, dass wir den Zeilenumbruch für jede Dimension separat behandeln können: %mHandeln auf den Realteil und %(n*1j)Handeln auf den Imaginärteil.

xnor
quelle
Schön gemacht. FWIW, mein bester Versuch ohne Verwendung einer komplexen Zahl ist 91 Bytes in Python 3.8.
Arnauld
@Arnauld Interessante Idee mit dem k:=x+y*m. Ich frage mich, ob es kürzer wäre, es kdirekt zu verwenden (x,y), x+y*manstatt es zu verwenden x+y*1j. Schade, dass Python 3 keine komplexen Module zulässt.
9.
Dieser Ansatz spart 5 Bytes in JS. :)
Arnauld
7

JavaScript (ES6), 67 Byte

m×n<32

Übernimmt die Eingabe als (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))``

Probieren Sie es online!

Damit es für jede Eingabe funktioniert, könnten wir BigInts für 73 Bytes verwenden :

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)

Probieren Sie es online!


JavaScript (ES6),  76 73  72 Byte

Übernimmt die Eingabe als (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)

Probieren Sie es online!

Kommentiert

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)
Arnauld
quelle
3

Haskell, 88 80 Bytes

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$[]

Probieren Sie es online!

Einfache Brute-Force- aMethode: Probieren Sie alle Aufwärts- / Rechtskombinationen aus, lassen Sie die Kreuzungspositionen fallen (wir behalten alle Positionen, die wir besucht haben, in der Liste ), und zählen Sie die Positionen, die irgendwann wieder die Position erreichen (0,0).

Der Grundfall der Rekursion ist, wenn wir eine Position ein zweites Mal besuchen ( elem(x,y)a). Das Ergebnis ist 0^0= 1wenn die Position ist (0,0)und zur Anzahl der Schleifen zählt oder 0( 0^xmit xNicht-Null) sonst und die Anzahl der Schleifen nicht erhöht.

Edit: -8 Bytes dank @xnor.

nimi
quelle
1
Die Basis Fällen können kombiniert werden |elem(x,y)a=0^(x+y), und (0!0)[]sein kann 0!0$[].
9.
2

Jelly , 44 Bytes

×ƝṪ2*Ḥ_2Rḃ€2ċⱮؽ%³¬ẠƲƇịØ.Ṛ,Ø.¤ZÄZ%€ʋ€³ŒQẠ$€S

Probieren Sie es online!

O(2mn)

mn

Nick Kennedy
quelle
1

Java 8, 120 Bytes

n->m->g(n,m,0,0);int g(int n,int m,int k,int l){return(l>>k)%2>0?k<1?1:0:g(n,m,(k+m)%(m*n),l|=1<<k)+g(n,m,k-~k%m-k%m,l);}

nm<32

Probieren Sie es online aus.

Kevin Cruijssen
quelle
1

CJam (50 Zeichen)

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

Online-Demo . Dies ist ein Programm, das zwei Eingaben von stdin übernimmt.

Endlich haben wir eine Antwort auf die Frage

Krieg, nicht wahr, wozu ist es gut?


Präparation

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
Peter Taylor
quelle
1

Jelly , 54 39 Bytes

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

Probieren Sie es online!

Ich habe dies als separate Antwort auf meine andere Gelee-Frage gepostet, weil es eine völlig andere Methode ist. Dies entspricht im Prinzip eher der Antwort von @ Arnauld. Es verwendet eine rekursive Funktion, die alle möglichen Pfade durchläuft, bis sie einen Punkt erreicht, an dem sie bereits angekommen ist, und dann das Ergebnis einer Überprüfung zurückgibt, ob sie wieder am Start ist. Ich vermute, dass noch ein paar Bytes abgeschabt werden könnten. Jetzt geändert, um den Slice-Operator zu verwenden. Es funktioniert gut für bis zu 5x5. Die Rekursionstiefe sollte höchstens mx n betragen.

Nick Kennedy
quelle