Siklus pada torus


20

Tantangan

Tantangan ini akan memiliki Anda menulis sebuah program yang mengambil dua bilangan bulat ndan mdan output jumlah non-berpotongan loop pada noleh mtorus yang dibuat oleh mulai (0,0)dan hanya mengambil langkah-langkah ke atas dan ke kanan. Anda dapat menganggap torus sebagai kisi-kisi dengan sampul di bagian atas dan bawah serta di samping.

Ini adalah sehingga byte paling sedikit menang.

Contoh

Misalnya, jika inputnya adalah n=m=5, satu jalan valid adalah

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

seperti yang ditunjukkan pada gambar.

Lingkaran pada torus.

Beberapa contoh input / output

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
m=n

Saya pikir torus juga memiliki sampul kiri-kanan. Haruskah kita menganggap itu hanya memiliki sampul atas-bawah saja? Contoh gambar sepertinya tidak menyiratkan seperti itu.
Erik the Outgolfer

@EriktheOutgolfer Gambar tidak menunjukkan jalur oranye yang membungkus dari kanan ke kiri, bukan?
Arnauld

@Arnauld Ya, tetapi itu tidak terlihat konsisten dengan deskripsi tantangan ("Anda dapat menganggap torus sebagai kisi dengan sampul di bagian atas dan bawah.")
Erik the Outgolfer

@EriktheOutgolfer Itu benar. Dan sekarang setelah Anda menyebutkannya, jalan biru itu salah. Itu harus terlebih dahulu membungkus dari kanan ke kiri dan kemudian dari atas ke bawah.
Arnauld

Jawaban:


4

Jelly , 28 byte

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

Tautan monadik yang menerima daftar [m,n],, yang menghasilkan hitungan.

TIO-jt1qe1v9 ... meskipun ada sedikit gunanya, itu terlalu tidak efisien.
(Saya bahkan tidak bisa menjalankan[2,3]secara lokal dengan ram 16GB)!

Bagaimana?

Brute force - menciptakan koordinat versi ubin yang cukup besar kemudian menyaring set daya dari titik-titik ini ke jalur dengan tetangga hanya meningkat satu per satu arah, kemudian menyaring mereka yang mulai dari koordinat minimal (yaitu asal) dan, pada saat yang sama, hapus koordinat awal ini dari masing-masing. Kemudian gunakan modulo aritmatika untuk membungkus kembali ke torus dan menyaring semua yang mengandung koordinat duplikat (yaitu yang mengandung persimpangan) dan, akhirnya, menyaring mereka yang memiliki koordinat akhir minimal (yaitu berakhir kembali pada titik asal) dan menghasilkan panjang hasil.

ạƝ§=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 byte

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

Cobalah online!

Yang menarik di sini adalah menggunakan bilangan kompleks zuntuk menyimpan koordinat posisi saat ini. Kita dapat naik dengan menambahkan 1dan bergerak ke kanan dengan menambahkan 1j. Yang mengejutkan saya, modulo bekerja pada bilangan kompleks dengan cara yang memungkinkan kita menangani pembungkus untuk setiap dimensi secara terpisah: melakukan %mtindakan pada bagian nyata, dan %(n*1j)bertindak pada bagian imajiner.


Bagus sekali. FWIW, upaya terbaik saya tanpa menggunakan angka kompleks adalah 91 byte di Python 3.8.
Arnauld

@Arnauld Ide yang menarik dengan k:=x+y*m. Itu membuat saya bertanya-tanya apakah akan lebih pendek untuk digunakan ksecara langsung untuk (x,y), menggunakan x+y*mdaripada x+y*1j. Sayang sekali Python 3 tidak memungkinkan modulus kompleks.
xnor


Pendekatan ini menghemat 5 byte dalam JS. :)
Arnauld

7

JavaScript (ES6), 67 byte

m×n<32

Mengambil input sebagai (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))``

Cobalah online!

Untuk membuatnya bekerja untuk input apa pun, kita bisa menggunakan BigInts untuk 73 byte :

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)

Cobalah online!


JavaScript (ES6),  76 73  72 byte

Mengambil input sebagai (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)

Cobalah online!

Berkomentar

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 byte

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

Cobalah online!

Simple brute force: coba semua kombinasi atas / kanan, menjatuhkan yang berpotongan (kami menjaga semua posisi yang kami kunjungi dalam daftar a) dan menghitung yang akhirnya mengenai posisi (0,0)lagi.

Kasus dasar dari rekursi adalah ketika kami mengunjungi posisi untuk kedua kalinya ( elem(x,y)a). Hasilnya adalah 0^0= 1ketika posisi adalah (0,0)dan diperhitungkan terhadap jumlah loop atau 0( 0^x, dengan xnon-nol) sebaliknya dan tidak menambah jumlah loop.

Edit: -8 byte terima kasih kepada @xnor.


1
Kasing dasar dapat digabungkan menjadi |elem(x,y)a=0^(x+y), dan (0!0)[]dapat 0!0$[].
xnor


1

Java 8, 120 byte

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

Cobalah online.


1

CJam (50 karakter)

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

Demo online . Ini adalah program yang mengambil dua input dari stdin.

Akhirnya kami punya jawaban untuk pertanyaan itu

Perang, ya, apa gunanya?


Pembedahan

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

Jelly , 54 39 byte

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

Cobalah online!

Saya telah memposting ini sebagai jawaban terpisah untuk Jelly saya yang lain karena ini adalah metode yang sama sekali berbeda. Ini pada prinsipnya lebih dekat dengan jawaban @ Arnauld. Ini menggunakan fungsi rekursif yang bekerja melalui setiap jalur yang mungkin sampai mencapai titik yang sudah harus, dan kemudian mengembalikan hasil pemeriksaan apakah itu kembali ke awal. Saya menduga beberapa byte lagi bisa dicukur. Sekarang diubah menjadi menggunakan operator slice. Ini bekerja dengan baik hingga 5x5. Kedalaman rekursi harus paling banyak mx n.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.