Цикли на торі


20

Виклик

Це завдання буде вам написати програму , яка приймає в двох цілих чисел nі mі виводить число непересічних петель на nна mторі , зроблених починаючи з (0,0)і тільки роблять кроки вгору і вправо. Ви можете думати про торус як сітку з обгортанням як вгорі, так і внизу та з боків.

Це тому виграє найменше байтів.

Приклад

Наприклад, якщо вхід є n=m=5, одна дійсна прогулянка

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

Я думаю, що торус також має оберт ліво-право. Чи слід вважати, що вона має лише обгортання вниз? Зразок зображення, схоже, не означає.
Ерік Покірний,

@EriktheOutgolfer На зображенні відображається помаранчевий шлях, який обертається справа наліво, чи не так?
Арнольд

@Arnauld Так, але це не відповідає опису виклику ("Ви можете думати про торус як сітку з обертом як вгорі, так і внизу")
Ерік Атгольфер

@EriktheOutgolfer Це правда. І тепер, коли ви це згадуєте, синій шлях неправильний. Спочатку він повинен обертатися справа наліво, а потім зверху вниз.
Арнольд

Відповіді:


4

Желе , 28 байт

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

Монадічна Посилання, що приймає список [m,n], який дає рахунок.

TIO-jt1qe1v9 ... хоча сенсу мало, це занадто неефективно.
(Я навіть не можу працювати[2,3]локально з 16 ГБ оперативної пам’яті)!

Як?

Брута сила - створює координати плиткової версії, достатньо великої, після чого фільтрує набір цих точок до тих контурів, у яких сусіди лише збільшуються на один в одному напрямку, потім фільтруються до тих, що починаються з мінімальної координати (тобто походження) і, в той же час видаляє цю початкову координату від кожного. Потім використовує арифметику по модулю, щоб повернутись до тору і відфільтрує будь-які містять подвійні координати (тобто ті, що містять перетини), і, нарешті, фільтрує ті, які мають мінімальні кінцеві координати (тобто закінчуються назад у початку) і дає довжину результату.

ạƝ§=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, моя найкраща спроба без використання складного числа - 91 байт у Python 3.8.
Арнольд

@Arnauld Цікава ідея з k:=x+y*m. Мене змушує замислитися, чи було б коротше використовувати kбезпосередньо для (x,y), x+y*mа не використовувати x+y*1j. Занадто поганий Python 3 не дозволяє складний модуль.
xnor


Такий підхід економить 5 байт у JS. :)
Арнольд

7

JavaScript (ES6), 67 байт

m×n<32

Вводиться як " (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))``

Спробуйте в Інтернеті!

Щоб він працював на будь-якому введенні, ми могли використовувати BigInts на 73 байти :

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)знову потрапляють на позицію .

Основний випадок рекурсії - це коли ми вдруге відвідуємо позицію ( elem(x,y)a). Результат 0^0= 1коли позиція є (0,0)і рахується до числа циклів або 0( 0^xпри xненульовому значенні) інакше і не збільшує кількість циклів.

Редагувати: -8 байт завдяки @xnor.


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.

Нарешті ми маємо відповідь на запитання

Війна, так, для чого це добре?


Розсічення

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Ç

Спробуйте в Інтернеті!

Я опублікував це як окрему відповідь на мою іншу желе, тому що це зовсім інший метод. Це в принципі ближче до відповіді @ Арнальда. Він використовує рекурсивну функцію, яка працює через кожен можливий шлях, поки не досягне точки, до якої вже дійшов, а потім повертає результат перевірки, чи повернувся він до початку. Я підозрюю, що ще кілька байт можуть бути поголені. Тепер перейдено до використання оператора зрізів. Він добре працює до 5x5. Глибина рекурсії повинна бути не більше mx n.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.