女王走过螺旋路


13

在遥远的王国中,国际象棋皇后每天沿着从1到1的螺旋路径散步n,而不希望跟随螺旋本身,而只是像在棋盘上那样做皇后的动作。女王深受她的臣民的喜爱,她们记下了她走过的每一个广场。假设女王可以在任何广场上开始步行并在任何广场上结束,那么她可以走的最短女王步行路程是什么?

挑战

给定矩形网格上的整数螺旋,编写一个函数,使用国际象棋皇后的动作返回此螺旋网格上两个数字之间的最短路径之一(由经过移动的单元数计算)。

例如,从1625

25 10 11 12 13
24  9  2  3 14
23  8  1  4 15
22  7  6  5 16
21 20 19 18 17

一些可能的路径包括16, 4, 2, 10, 2516, 5, 1, 9, 25

规则

  • 输入将是任何两个正整数。
  • 输出将是仅使用正交和对角线移动的整个螺旋路径的整数(包括两个端点)。
  • 路径的长度由行进的细胞数计算。
  • 您的答案可能是程序或函数。
  • 这是代码高尔夫,因此最少的字节数获胜。

与往常一样,如果问题仍然不清楚,请告诉我。祝你好运,打高尔夫球!

测试用例

>>> queen_spiral(4, 5)
4, 5
>>> queen_spiral(13, 20)
13, 3, 1, 7, 20
>>> queen_spiral(14, 14)
14
>>> queen_spiral(10, 3)
10, 11, 3
>>> queen_spiral(16, 25)
16, 4, 2, 10, 25
>>> queen_spiral(80, 1)
80, 48, 24, 8, 1


5
您可能想提一提,您正在寻找的最短路径是经过的细胞数(例如,与欧几里得距离相对)。
Martin Ender

1
作为“国王之行”,这更有意义吗?
乔金

1
@JoKing Ah,既然您提到它,那应该是国王的散步。但是,更改标题可能为时已晚。
Sherlock

Answers:


5

APL(Dyalog Unicode)59 57字节SBCS

{v⍳+\v[⍺],↓⍉↑(|⍴¨×)⊃⍵⍺-.⊃⊂v9 11∘○¨+\0,0j1*{⍵/⍨⌈⍵÷2}⍳⍺⌈⍵}

在线尝试!

-2个字节,感谢@ngn。

接受两个端点作为左参数和右参数的匿名函数。

取消高尔夫及其运作方式

女王/王后先对角线移动,因此足以预先计算每个数字的坐标max(start,end)

坐标生成算法的灵感来自于有关挑战的几个答案,但与任何现有答案略有不同:

  • 给定10的必要范围
  • 生成基于1的范围 r=1 2 3 4 5 6 7 8 9 10
  • 取每个数字一半的上限 n=1 1 2 2 3 3 4 4 5 5
  • 复制的每个项目r通过n1 2 3 3 4 4 5 5 5 6 6 6 7 7 7 7 8 8 8 8 9 9 9 9 9 10 10 10 10 10
  • 以起点为0的假想单位的累积乘方和。(这是链接挑战的各种Python解决方案所共有的部分)

然后,一旦坐标向量v准备就绪,我们就可以使用v[i]和轻松地在螺旋索引和坐标之间进行转换v⍳coord(找到coordin 的第一个索引v)。

 Define a function; ⍺=start, ⍵=end
f←{
   Construct a vector of spiral coordinates v
  v9 11∘○¨+\0,0j1*{⍵/⍨⌈⍵÷2}⍳⍺⌈⍵
                             ⍺⌈⍵   max of start, end
                                  range of 1 to that number
                   {⍵/⍨⌈⍵÷2}   for each number n of above, copy itself ceil(n/2) times
               0j1*   raise imaginary unit to the power of above
           +\0,       prepend 0 and cumulative sum
                      (gives vector of coordinates as complex numbers)
    9 11∘○¨   convert each complex number into (real, imag) pair
  v          assign it to v

   Extract start and end coordinates
  a w←(⍺⊃v)(⍵⊃v)

   Compute the path the Queen will take
  v⍳+\(a),↓⍉↑(|⍴¨×)w-a
                    w-a   coordinate difference (end-start)
              (|⍴¨×)      generate abs(x) copies of signum(x) for both x- and y-coords
                          e.g. 4 -> (1 1 1 1), ¯3 -> 1 ¯1 ¯1)
           ↓⍉↑   promote to matrix (with 0 padding), transpose and split again
                 (gives list of steps the Queen will take)
    +\(a),      prepend the starting point and cumulative sum
                 (gives the path as coordinates)
  v   index into the spiral vector (gives the spiral numbers at those coordinates)
}

(⍵⊃v)-⍺⊃v->⊃⍵⍺-.⊃⊂
ngn

(⍺⌷v)->v[⍺]
ngn

3

Mathematica 615530字节

这将构造一个数字网格,将其转换为图形,然后在输入的两个数字之间找到最短路径。


松散

numberSpiral来自Mathworld Prime Spiral。它创建一个n n n Ulam Spiral(不突出质数)。

findPath将数字网格转换为图形。边缘是数字网格上的有效皇后移动。


numberSpiral[n_Integer?OddQ]:= 
  Module[{a,i=(n+1)/2,j=(n+1)/2,cnt=1,dir=0,len,parity,vec={{1,0},{0,-1},{-1,0},{0,1}}},a=Table[j+n(i-1),{i,n},{j,n}];Do[Do[Do[a[[j,i]]=cnt++;{i,j}+=vec[[dir+1]],{k,len}];dir=Mod[dir+1,4],{parity,0,1}],{len,n-1}];a];  

findPath[v1_, v2_] := 
  Module[{f, z, k},
    (*f  creates edges between each number and its neighboring squares *)
    f[sp_,n_]:=n<->#&/@(sp[[Sequence@@#]]&/@(Position[sp,n][[1]]/.{r_,c_}:>Cases[{{r-1,c},{r+1,c},{r,c-1},{r,c+1},{r-1,c-1},{r-1,c+1},{r+1,c+1}, {r+1,c-1}},{x_,y_}/; 0<x<k&&0<y<k]));k=If[EvenQ[
     z=\[LeftCeiling]Sqrt[Sort[{v1, v2}][[-1]]]\[RightCeiling]],z+1,z];
    FindShortestPath[Graph[Sort/@Flatten[f[ns=numberSpiral[k],#]&/@Range[k^2]] //Union],v1,v2]]

例子

findPath[4,5]
findPath[13,22]
findPath[16,25]
numberSpiral[5]//Grid

{4,5}

{13,3,1,7,22}

{16,4,1,9,25}

格线


从80到1的最短路径包含5个顶点,而不是6个顶点。

findPath[80,1]
numberSpiral[9]//Grid

{80,48,24,8,1}

八十一格


打高尔夫球

u=Module;
w@n_:=u[{a,i=(n+1)/2,j=(n+1)/2,c=1,d=0,l,p,v={{1,0},{0,-1},{-1,0},{0,1}}},
a=Table[j+n(i-1),{i,n},{j,n}];
Do[Do[Do[a[[j,i]]=c++;{i,j}+=v[[d+1]],{k,l}];d=Mod[d+1,4],{p,0,1}],{l,n-1}];a];
h[v1_,v2_]:=u[{f,z},
s_~f~n_:=n<->#&/@(s[[Sequence@@#]]&/@(Position[s,n][[1]]/.{r_,c_}:> 
Cases[{{r-1,c},{r+1,c},{r,c-1},{r,c+1},{r-1,c-1},{r-1,c+1},{r+1,c+1},{r+1,c-1}},{x_,y_}/;0<x<k&&0<y<k]));
k=If[EvenQ[z=\[LeftCeiling]Sqrt[Sort[{v1,v2}][[-1]]]\[RightCeiling]],z+1,z];
FindShortestPath[g=Graph[Sort/@Flatten[f[ns=w@k,#]&/@Union@Range[k^2]]],v1,v2]]

2

Scala(830位元组)

使用四个相互递归的函数在正方形2D数组中构建螺旋。另一个递归搜索以构建路径列表。

def P(s:Int,e:Int):List[Int]={
import scala.math._
type G=Array[Array[Int]]
type I=Int
type T=(I,I)
def S(z:I)={def U(g:G,x:I,y:I,c:I,r:I):Unit={for(i<-0 to r.min(y)){g(y-i)(x)=c+i}
if(r<=y)R(g,x,y-r,c+r,r)}
def R(g:G,x:I,y:I,c:I,r:I)={for(i<-0 to r){g(y)(x+i)=c+i}
D(g,x+r,y,c+r,r+1)}
def D(g:G,x:I,y:I,c:I,r:I)={for(i<-0 to r){g(y+i)(x)=c+i}
L(g,x,y+r,c+r,r)}
def L(g:G,x:I,y:I,c:I,r:I)={for(i<-0 to r){g(y)(x-i)=c+i}
U(g,x-r,y,c+r,r+1)}
val g=Array.ofDim[I](z,z)
U(g,z/2,z/2,1,1)
g}
def C(n:I,g:G):T={var(x,y)=(0,0)
for(i<-g.indices){val j=g(i).indexOf(n)
if(j>=0){x=j
y=i}}
(x,y)}
def N(n:Int)=if(n==0)0 else if(n<0)-1 else 1
def Q(a:T,b:T):List[T]={val u=N(b._1-a._1)
val v=N(b._2-a._2)
if(u==0&&v==0)b::Nil else a::Q((a._1+u,a._2+v),b)}
val z=ceil(sqrt(max(s,e))).toInt|1
val p=S(z)
Q(C(s,p),C(e,p)).map{case(x,y)=>p(y)(x)}}

不打高尔夫球

  import scala.math._
  type Grid=Array[Array[Int]]
  def spiral(size: Int) = {
    def up(grid:Grid, x: Int, y: Int, c: Int, r: Int): Unit = {
      for (i <- 0 to r.min(y)) {
        grid(y-i)(x) = c + i
      }
      if (r <= y)
        right(grid,x,y-r,c+r,r)
    }
    def right(grid:Grid, x: Int, y: Int, c: Int, r: Int) = {
      for (i <- 0 to r) {
        grid(y)(x+i) = c + i
      }
      down(grid,x+r,y,c+r,r+1)
    }
    def down(grid:Grid, x: Int, y: Int, c: Int, r: Int) = {
      for (i <- 0 to r) {
        grid(y+i)(x) = c + i
      }
      left(grid,x,y+r,c+r,r)
    }
    def left(grid:Grid, x: Int, y: Int, c: Int, r: Int) = {
      for (i <- 0 to r) {
        grid(y)(x-i) = c + i
      }
      up(grid,x-r,y,c+r,r+1)
    }
    val grid = Array.ofDim[Int](size,size)
    up(grid,size/2,size/2,1,1)
    grid
  }
  def findPath(start: Int, end: Int): List[Int] = {
    def findCoords(n: Int, grid: Grid): (Int, Int) = {
      var (x,y)=(0,0)
      for (i <- grid.indices) {
        val j = grid(i).indexOf(n)
        if (j >= 0) {
          x = j
          y = i
        }
      }
      (x,y)
    }
    def sign(n: Int) = if (n == 0) 0 else if (n < 0) -1 else 1
    def path(stc: (Int, Int), enc: (Int, Int)) : List[(Int, Int)] = {
      val dx = sign(enc._1 - stc._1)
      val dy = sign(enc._2 - stc._2)
      if (dx == 0 && dy == 0) {
        enc :: Nil
      } else {
        stc :: path((stc._1 + dx, stc._2 + dy), enc)
      }
    }
    val size = ceil(sqrt(max(start, end))).toInt | 1
    val spir = spiral(size)
    path(findCoords(start, spir),findCoords(end, spir)).
      map { case (x, y) => spir(y)(x) }
  }

2

红宝石,262个 218 216字节

这是我的Python回答的一部分。欢迎打高尔夫球。

编辑: 45字节感谢约旦和他们的意见d=[0]*n=m*m;*e=c=0;*t=a.rect0<=>xx,y=(e[a]-g=e[b]).rect; t<<d[(g.real+x)*m+g.imag+y]。从(x+y*1i)到的另一个字节(x+y.i)

->a,b{m=([a,b].max**0.5).to_i+1;d=[0]*n=m*m;*e=c=0;*t=a
n.times{|k|d[c.real*m+c.imag]=k+1;e<<c;c+=1i**((4*k+1)**0.5-1).to_i}
x,y=(e[a]-g=e[b]).rect
(x+=0<=>x;y+=0<=>y;t<<d[(g.real+x)*m+g.imag+y])while(x+y.i).abs>0
t}

取消高尔夫:

def q(a,b)
  m = ([a,b].max**0.5).to_i+1
  n = m*m
  d = [0]*n
  c = 0
  *e = c   # same as e=[0]
  *t = a   # same as t=[a]

  (1..n).each do |k|
    d[c.real * m + c.imag] = k+1
    e << c
    c += 1i**((4*k+1)**0.5-1).to_i
  end

  x, y = (e[a] - g=e[b]).rect

  while (x+y.i).abs > 0 do
    if x<0
      x += 1
    elsif x>0
      x += -1
    end

    if y<0
      y += 1
    elsif y>0
      y -= 1
    end

    t << d[(g.real+x)*m+g.imag+y]
  end

  return t
end

您应该q=从答案中删除,因为您没有计算其字节数。c=0;e=[c];t=[a]可以缩短为*e=c=0;*t=a。您可以替换z=e[a]-e[b];x,y=z.real,z.imag使用x,y=(e[a]-e[b]).rect,并x+=x<0?1:x>0?-1:0x+=0<=>x(同为y)。我认为它可以减少到229个字节。
约旦

如果切换到一维数组,则可以再保存6个字节。更换的初始化dd=[0]*m*m,然后替换d[c.real][c.imag]d[c.real*m+c.imag]d[e[b].real+x][e[b].imag+y]d[(e[b].real+x)*m+e[b].imag+y]
约旦

与我之前的评论相比,改进了2个字节:t<<d[(e[b].real+x)*m+e[b].imag+y]可以缩短为u,v=e[b].rect;t<<d[(u+x)*m+v+y]
约旦

更改d=[0]*m*md=[0]*n=m*m和,(m*m).times再增加两个字节n.times。那是219。–
约旦

您可以通过将更x,y=(e[a]-e[b]).rect改为x,y=(e[a]-g=e[b]).rect,删除u,v=e[b].rect和更改t<<d[(u+x)*m+v+y]t<<d[(g.real+x)*g.imag+v+y](基本上恢复倒数第二条注释)来节省另外两个字节。
约旦

1

Python 3,316个字节

这个答案看的坐标a,并b在螺旋(用复数),并增加了对角移动,然后再正交移动。

def q(a,b):
 m=int(max(a,b)**.5)+1;d=[];c=0;e=[c];t=[a]
 for i in range(m):d+=[[0]*m]
 for k in range(m*m):d[int(c.real)][int(c.imag)]=k+1;e+=[c];c+=1j**int((4*k+1)**.5-1)
 z=e[a]-e[b];x,y=int(z.real),int(z.imag)
 while abs(x+y*1j):x+=(x<0)^-(x>0);y+=(y<0)^-(y>0);t+=[d[int(e[b].real)+x][int(e[b].imag)+y]]
 return t

取消高尔夫:

def queen_spiral(a,b):
    square_size = int(max(a,b)**.5)+1
    complex_to_spiral = []
    complex = 0
    spiral_to_complex = [c] # add 0 first, so that it's 1-indexed later
    result = [a]

    for i in range(square_size):
        complex_to_spiral.append([0]*square_size) # the rows of the spiral

    for k in range(square_size**2):
        row = int(complex.real)
        column = int(complex.imag)
        complex_to_spiral[row][column] = k+1 # 1-indexing

        spiral_to_complex.append(complex)

        quarter_turns = int((4*k+1)**.5-1)
        complex += 1j**quarter_turns

    z = spiral_to_complex[a] - spiral_to_complex[b]
    v = spiral_to_complex[b]
    x, y = int(z.real), int(z.imag)
    r, s = int(v.real), int(v.imag)

    while abs(x+y*1j):
        if x < 0:
            x += 1
        elif x > 0:
            x += -1
        # else x == 0, do nothing
        if y < 0:
            y += 1
        elif y > 0:
            y += -1

        vertex = complex_to_spiral[r+x][s+y]
        result.append(vertex)
    return result
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.