在圆环上循环


20

挑战

这一挑战将让你写一个程序,它在两个整数nm输出的数量不相交的环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

@Arnauld是的,但是看起来与挑战的描述不一致(“您可以将环面视为顶部和底部都环绕的网格。”)
Egg the Outgolfer

@EriktheOutgolfer是的。现在您提到了,蓝色的道路是错误的。它应该首先从右到左环绕,然后从上到下环绕。
Arnauld

Answers:


4

果冻,28 个字节

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

接受列表的单子链接[m,n],产生计数。

TIO-jt1qe1v9 ...虽然没有什么意义,但效率太低了。
(我什至无法在[2,3]本地使用16GB内存运行)!

怎么样?

蛮力-创建足够大的平铺版本的坐标,然后将这些点的幂集过滤到那些路径,而相邻路径仅在一个方向上增加一个,然后过滤到以最小坐标(即原点)开始的那些,同时,从每个坐标中删除该起始坐标。然后使用取模算法回卷,并过滤掉任何包含重复坐标的对象(即包含交点的坐标),最后过滤到具有最小结束坐标的对象(即以原点结束的坐标)并得出结果的长度。

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

@Arnauld与有趣的想法k:=x+y*m。它使我想知道,k直接使用for (x,y)x+y*m而不是,会不会更短x+y*1j。太糟糕的Python 3不允许复数模量。
xnor


这种方法在JS中节省了5个字节。:)
Arnauld

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)00^xx

编辑:-8字节感谢@xnor。


1
基本案例可以组合为|elem(x,y)a=0^(x+y),也(0!0)[]可以为0!0$[]
xnor


1

Java 8,120字节

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

在线尝试。


1

果酱(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Ç

在线尝试!

我将其发布为其他果冻的单独答案,因为这是一种完全不同的方法。原则上,这与@Arnauld的答案更接近。它使用递归函数,该递归函数遍历所有可能的路径,直到到达已经到达的点,然后将检查结果返回到起点。我怀疑可能会删除更多的字节。现在更改为使用切片运算符。它适用于高达5x5的效果。递归深度应最大为mx n。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.