查找纵火犯的摇篮曲


26

想象一下一个纵火犯在城镇中走来走去,并按照一种非常特定的方式挑选受害者(或者,想象一下一只蜜蜂在花园里飞来飞去,并按照一种非常特定的方式挑选花朵进行花粉授粉)。假设城镇是一个N×N矩阵,其中N是大于或等于2的整数。纵火犯从左上角开始,依次将房屋M点设置在房屋前方(其中M是他们当前所在房屋的编号),同时按顺序更改每次火灾后房屋的移动方向东⟶南⟶西⟶北⟶东⟶南...依此类推。该摇篮曲纵火犯的价值是使他们离开城镇的M值(即,他们在停止憎恶之前所参观的最后一所房屋)。通过示例更容易理解。以以下矩阵为例:

3 2 3 2 7
3 1 4 1 6
2 5 3 1 1
4 4 3 2 4
1 1 1 1 1
  • 我们从左上角开始,所以M = 3X标记纵火犯的当前位置和先前位置):
    X 2 3 2 7
    3 1 4 1 6
    2 5 3 1 1
    4 4 3 2 4
    1 1 1 1 1
    
  • 根据已知顺序,它首先向东移动M(3)个点,并降落在2个点上,因此M相应地发生变化:
    X 2 3 X 7
    3 1 4 1 6
    2 5 3 1 1
    4 4 3 2 4
    1 1 1 1 1
    
  • 然后它向南走2点,M现在是1
    X 2 3 X 7
    3 1 4 1 6
    2 5 3 X 1
    4 4 3 2 4
    1 1 1 1 1
    
  • 现在它向西移动1个点,M变为3
    X 2 3 X 7
    3 1 4 1 6
    2 5 XX 1
    4 4 3 2 4
    1 1 1 1 1
    
  • 向北移动3个景点后,就离开了小镇!因此,3是该纵火犯的摇篮曲:
        X
    X 2 3 X 7
    3 1 4 1 6
    2 5 XX 1
    4 4 3 2 4
    1 1 1 1 1
    

给定一个N×N矩阵(您也可以选择将N用作输入),找到纵火犯的摇篮曲。我编写了一个程序,可以使用它生成更多测试用例并可视化纵火犯的路径:在线尝试!

  • 您可以假设纵火犯确实有摇篮曲(也就是说,它实际上可以脱离矩阵)。
  • 为简单起见,矩阵将仅包含小于或等于9(数字)的正整数。完全欢迎处理任何正整数的解决方案。
  • 请注意,纵火犯可以将其降落在已经被烧毁的地方,以防他们搬进来的感觉不同于第一次。在这种情况下,只需获取该元素的值,然后像往常一样再次移动即可。
  • 您可以使用任何编程语言进行竞争,并且可以通过任何标准方法接受输入并提供输出,同时请注意,默认情况下会禁止这些漏洞。这是,因此每种语言的最短提交(以字节为单位)将获胜。

测试用例

-------------
9 2 3
1 7 2
8 7 6

摇篮曲:9
-------------
2 1 2 1
3 1 1 2
1 2 2 1
1 1 1 3

摇篮曲:2
-------------
3 2 3 2 7
3 1 4 1 6
2 5 3 1 1
4 4 3 2 4
1 1 1 1 1

摇篮曲:3
-------------
1 2 1 2 1 2
1 2 1 2 1 2
1 2 1 2 1 2
1 2 1 2 1 2
1 2 1 2 1 2
1 2 1 2 1 2

摇篮曲:2
-------------
3 2 1 2 1 1 1
2 3 2 3 2 1 1
2 1 1 1 3 1 2
3 1 1 1 1 1 1
4 5 2 3 1 1 1
1 2 1 2 1 2 2
1 2 2 3 2 1 2

摇篮曲:3
-------------

格式不同的矩阵:

[[9,2,3],[1,7,2],[8,7,6]]
[[2,1,2,1],[3,1,1,2],[1,2,2,1],[1,1,1,3]]
[[3,2,3,2,7],[3,1,4,1,6],[2,5,3,1,1],[4,4,3,2,4],[ 1,1,1,1,1]]
[[1、2、1、2、1、2],[1、2、1、2、1、2],[1、2、1、2、1、2],[1、2、1, 2,1,2],[1、2、1、2、1、2],[1、2、1、2、1、2]
[[3,2,1,2,1,1,1,1],[2,3,2,3,2,1,1],[2,1,1,1,3,1,2],[ 3,1,1,1,1,1,1,1],[4,5,2,3,1,1,1],[1,2,1,2,1,2,2,2],[1, 2,2,3,2,1,2]]

第五个测试用例的可视化非常有趣


1
这就像在二维上将“像兔子一样跳过”一般化,目标略有不同。这一挑战,它的标题的主题是灵感来自一首由霍齐尔
Xcoder先生

当纵火犯降落在已经烧毁的正方形上时会发生什么?
水平河

2
我们是否可以假定纵火犯实际上不是纵火犯,而是在每个位置都做得很好而不是将其烧掉?+1是个很好的主意:)
ElPedro '18年

2
@ElPedro Sure,为您准备的替代版本:想象一只蜜蜂在花园中飞来飞去,并按照非常特定的模式采摘花朵进行花粉处理。:D快乐友好打高尔夫球!
Xcoder先生18年

1
这是一个更好的想法。如果我可以再次投票,我会赞成。
ElPedro '18年

Answers:


11

MATL,32字节

JQ6*`G5thYay&Zj3$)wyJ2@-^*+8M]b&

在线尝试!验证所有测试用例

怎么运行的

输入矩阵填充有五个零的帧,因此例如

3 2 3 2 7
3 1 4 1 6
2 5 3 1 1
4 4 3 2 4
1 1 1 1 1

变成

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 3 2 3 2 7 0 0 0 0 0
0 0 0 0 0 3 1 4 1 6 0 0 0 0 0
0 0 0 0 0 2 5 3 1 1 0 0 0 0 0
0 0 0 0 0 4 4 3 2 4 0 0 0 0 0
0 0 0 0 0 1 1 1 1 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

零帧用于检测纵火蜂何时离开矩阵。具有五个零的扩展名确保从任何非零条目到任何方向的长度方向上的模块化位移都9将正确地降为零,而不会回绕到某些非零条目。

在矩阵坐标中,蜜蜂从(6,6)扩展矩阵的入口开始。它读取该条目,并根据需要更新坐标,并在相应方向上应用读取长度的(模块化)位移。循环重复此过程,直到读取的值为0。在该条目之前读取的条目(即最后一个非零条目)是输出。

坐标实际上存储为复数,因此(6,6)变为6+6j。这样,可以将四个循环方向实现为虚单位的幂。对应的功率(j1-j-1)由读取条目以获得复杂的位移,其用于更新坐标相乘。

连续读取的值将保留在堆栈中。退出循环时,堆栈按顺序包含所有非零读取值,然后是最后一个读取值0,然后是最新的复数坐标。因此,排在第三位的元素是必需的输出。


1
+1是一种非常新颖的方法。
LastStar007 '18

7

JavaScript(ES6),70 68字节

m=>(g=d=>(n=(m[y]||0)[x])?g(--d&3,x-=d%2*(y+=--d%2*n,L=n)):L)(x=y=0)

在线尝试!

已评论

m => (                        // given m = input matrix
  g = d =>                    // g = recursive function taking the direction d
    (n = (m[y] || 0)[x]) ?    // let n be the content of the current cell; if it's defined:
      g(                      //   do a recursive call:
        --d & 3,              //     with the next direction (0 = E, 3 = S, 2 = W, 1 = N)
        x -=                  //     update x by subtracting ...
          d % 2 * (           //       ... ((d - 1) % 2) * n
            y += --d % 2 * n, //       and update y by adding ((d - 2) % 2) * n
            L = n             //       save n into L
          )                   //     end of x update
      )                       //   end of recursive call
    :                         // else:
      L                       //   stop recursion and return L
)(x = y = 0)                  // initial call to g() with x = y = d = 0

鉴于JS中取模的符号是除数的符号,因此可以通过以下方式更新方向:

 d | d' = --d&3 | dx = -(d%2)  | dy = --d%2 | direction
---+------------+--------------+------------+------------------
 0 |     3      | -(-1%2) = +1 | -2%2 =  0  | (+1,  0) = East
 3 |     2      | -( 2%2) =  0 |  1%2 = +1  | ( 0, +1) = South
 2 |     1      | -( 1%2) = -1 |  0%2 =  0  | (-1,  0) = West
 1 |     0      | -( 0%2) =  0 | -1%2 = -1  | ( 0, -1) = North

4

木炭25 18字节

PS↶WKK«≔ιθ×Iι¶↷»⎚θ

在线尝试!链接是详细版本的代码。说明:

PS

打印输入字符串,但不要移动打印位置。

向左旋转枢轴,使打印方向向上。

WKK«

在打印位置下有一个字符时重复上述步骤。

≔ιθ

将字符保存在变量中。

×Iι¶

将字符转换为数字并打印许多换行符。由于现在打印方向朝上,因此最终可以水平打印。结果是我们已将打印位置沿所需的方向移动了打印位置下的数字所指定的数量。

↷»

旋转枢轴,以便下一个换行符可以在下一个循环中沿顺时针方向在下一个方向上移动打印位置。

F⟦ωθ⟧¿ιι⎚

不幸的是,我们仍然有混乱的画布输入,更不幸的是,如果我们清除画布,我们也会清除变量。因此,这有点技巧:空字符串和变量的列表将循环遍历。在循环的第一遍,循环变量为空,因此画布和循环变量以及结果变量均被清除。但是循环还没有结束!在循环的第二遍,我们仍然可以访问已仔细保存在循环列表中的变量。它只是剩下来打印。

⎚θ

清除画布并打印保存的变量。(感谢@ ASCII-only来修复木炭。)



2

木炭50 49 46 34 33 26字节

NθEθSMθ↑WKK«MIι✳⊗Lυ⊞υι»⎚⊟υ

在线尝试

链接是该代码的详细版本

输入必须在其自己的行上为N,然后将数组的行放在单独的行上。

任何可以减少字节的方法都是受欢迎和需要的,因为我不是木炭方面的好高尔夫球手!

-12个字节感谢@Neil!-1字节感谢@ ASCII-only!-7个字节(仅使用@ASCII Clear)(更改了一个使重置变量变为错误的错误)


1

红色,145字节

func[b][h:[0 1 0 -1 0]x: y: 1 i: 0
until[y: h/(i: i % 4 + 1) *(t: b/(y)/(x)) + y x: h/(i + 1) * t + x none = b/(y) or(x < 1 or(x > length? b))]t]

在线尝试!

更具可读性:

f: func[b][
    h: [0 1 0 -1 0]                                ; step lengths (combined for x and y) 
    x: y: 1                                        ; starting coords (1,1)
    i: 0                                           ; step counter 
    until[
        y: h/(i: i % 4 + 1) * (t: b/(y)/(x)) + y   ; next y; t stores the lullaby
        x: h/(i + 1) * t + x                       ; next x
        none = b/(y) or (x < 1 or (x > length? b)) ; until x or y are not valid indices
    ]
    t                                              ; return the lullaby
]


1

干净,141字节

import StdEnv
d=[0,1,1,0,0,-1,-1,0:d]
$m[x,y]n[a,b:l]#r=size m
#u=x+a*n
#v=y+b*n
|0>u||0>v||u>=r||v>=r=n= $m[u,v]m.[u,v]l
?m= $m[0,0]m.[0,0]d

在线尝试!

定义函数? :: {#{#Int}} -> Int,获取整数的未装箱的数组的未装箱的数组并返回结果。


1

Java 8,121字节

m->{int l=m.length,x=0,y=0,f=0,r=0;for(;x*y>=0&x<l&y<l;x+=f<1?r:f==2?-r:0,y+=f==1?r:f>2?-r:0,f=++f%4)r=m[y][x];return r;}

在线尝试。

具有相同121字节字节数的替代方法:

m->{int l=m.length,x=0,y=0,f=0,r=0;try{for(;;x+=f<1?r:f==2?-r:0,y+=f==1?r:f>2?-r:0,f=++f%4)r=m[y][x];}finally{return r;}}

使用try-finally而不是检查x,y-coordinate是否仍在范围内。

在线尝试。

说明:

m->{                   // Method with integer-matrix parameter and integer return-type
  int l=m.length,      //  Dimensions of the matrix
      x=0,y=0,         //  x,y coordinate, starting at [0,0]
      f=0,             //  Direction-flag, starting at 0 (east)
      r=0;             //  Result-integer
  for(;x*y>=0&x<l&y<l  //  Loop as long as the x,y coordinates are still within bounds
      ;                //    After every iteration:
       x+=f<1?         //     If the direction is east:
           r           //      Increase the `x` coordinate by `r`
          :f==2?       //     Else-if the direction is west:
           -r          //      Decrease the `x` coordinate by `r`
          :            //     Else (it's north/south):
           0,          //      Leave the `x` coordinate the same
       y+=f==1?        //     If the direction is south:
           r           //      Increase the `y` coordinate by `r`
          :f>2?        //     Else-if the direction is north:
           -r          //      Decrease the `y` coordinate by `r`
          :            //     Else:
           0,          //      Leave the `y` coordinate the same
       f=++f%4)        //     Go to the next direction (0→1→2→3→0)
    r=m[y][x];         //   Set `r` to the value of the current cell
  return r;}           //  Return the last `r` before we went out of bounds

0

Perl 5,92个字节

sub b{1while eval join'&&',map{/./;map"(\$$_$&=".'$n=$_[$y][$x])'.$',x,'y'}'+<@_','->=0';$n}

在线尝试!

怎么样?

嵌套映射集和联接产生以下结果:

($x+=$n=$_[$y][$x])<@_&&($y+=$n=$_[$y][$x])<@_&&($x-=$n=$_[$y][$x])>=0&&($y-=$n=$_[$y][$x])>=0

然后评估该值以确定循环是否结束。因为布尔值是从左到右求值的,所以在求值过程中,$n实际值会更改(最多)四次。由于布尔逻辑在Perl中短路,因此$n退出循环时的值为摇篮曲。


0

Python 3中85 84个字节

xcoder:-1(我不记得+〜的把戏)

def f(x):
 r=c=0
 while-1<r:d=x[r][c];r,c=len(x)-c+~d,r;x=[*zip(*x)][::-1]
 return d

在线尝试!

此解决方案始终向东移动并在每次移动后逆时针旋转网格,而不是沿不同方向(E,S,W,N)移动。旋转后,最后一列现在是第一行,因此如果行索引小于零,则意味着我们脱离了董事会。



0

视网膜,161字节

.
 $.%`*_#$&*
(?<=(.+¶)+|^)
A ¶A$#1*
~(K`{`^X\1YZ¶1S$4¶1XYZ¶2$4$2$4$3¶2XYZ¶3S¶3XY\1Z¶S
X
(_$*)(A_$*)
Y
( _$*)
Z
(?=\n\D$*\2\b.$*\3#(_+))
)`S
$$4$$2$$3
L$0`_+
$.0

在线尝试!

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.