曼哈顿三角距离


26

规则网格上的曼哈顿距离是一个人需要一个正交的步数才能到达另一个单元。正交步是穿过网格单元边缘的步(相对于拐角,这会给我们切比雪夫距离)。

我们可以在其他网格(例如三角形网格)上定义相似的距离。我们可以使用以下索引方案寻址网格中的各个单元,其中每个单元包含一x,y对:

    ____________________________________...
   /\      /\      /\      /\      /\
  /  \ 1,0/  \ 3,0/  \ 5,0/  \ 7,0/  \
 / 0,0\  / 2,0\  / 4,0\  / 6,0\  / 8,0\
/______\/______\/______\/______\/______\...
\      /\      /\      /\      /\      /
 \ 0,1/  \ 2,1/  \ 4,1/  \ 6,1/  \ 8,1/
  \  / 1,1\  / 3,1\  / 5,1\  / 7,1\  /
   \/______\/______\/______\/______\/___...
   /\      /\      /\      /\      /\
  /  \ 1,2/  \ 3,2/  \ 5,2/  \ 7,2/  \
 / 0,2\  / 2,2\  / 4,2\  / 6,2\  / 8,2\  
/______\/______\/______\/______\/______\...
\      /\      /\      /\      /\      /
 \ 0,3/  \ 2,3/  \ 4,3/  \ 6,3/  \ 8,3/
  \  / 1,3\  / 3,3\  / 5,3\  / 7,3\  /
   \/______\/______\/______\/______\/___...
   /\      /\      /\      /\      /\
  .  .    .  .    .  .    .  .    .  .
 .    .  .    .  .    .  .    .  .    .

现在,此网格上的曼哈顿距离再次是从一个单元格到另一个单元格的最小边跨步数。因此,您可以从3,1移至2,14,13,2,但不能移至任何其他三角形,因为那将是交叉点而不是边缘。

例如,从远处2,15,24。最短的路径通常不是唯一的,但是以4个步骤进行距离的一种方法是:

2,1 --> 3,1 --> 3,2 --> 4,2 --> 5,2

挑战

给定两个坐标对,并根据上述寻址方案,返回它们之间的曼哈顿距离。x1,y1x2,y2

您可以假定所有四个输入都是非负整数,每个输入均小于128。您可以按任何顺序将它们取任意值并任意分组(四个单独的参数,四个整数的列表,两对整数,一个2x2矩阵,.. )。

您可以编写程序或函数,并使用接收输入和提供输出的任何标准方法

您可以使用任何编程语言,但是请注意,默认情况下,这些漏洞是禁止的。

这是,因此以字节为单位的最短有效答案为准。

测试用例

每个测试用例均以给出。x1,y1 x2,y2 => result

1,2 1,2 => 0
0,1 1,1 => 1
1,0 1,1 => 3
2,1 5,2 => 4
0,0 0,127 => 253
0,0 127,0 => 127
0,0 127,127 => 254
0,127 127,0 => 254
0,127 127,127 => 127
127,0 127,127 => 255
75,7 69,2 => 11
47,58 36,79 => 42
77,9 111,23 => 48
123,100 111,60 => 80
120,23 55,41 => 83
28,20 91,68 => 111
85,107 69,46 => 123
16,25 100,100 => 159
62,85 22,5 => 160
92,26 59,113 => 174
62,22 35,125 => 206

那些获得净负面评价的漏洞是否包括在官方漏洞中?
DavidC

@DavidC编号。从漏洞问题开始:“ [...]在任何答案中描述的漏洞为+5或更高,并且其投票数至少是投票数的两倍,可以被认为是社区不可接受的。 “
Martin Ender

我们是否可以接受第五个输入,默认情况下从0开始(结果)?然后,我无需在回答中添加(a,b,x,y)->c(a,b,x,y,0)c使用四个参数并0作为第五个参数调用分离的方法)。
凯文·克鲁伊森

3
@KevinCruijssen对不起。另外,固定参数太容易滥用了(在特殊情况下只允许0看起来很奇怪)。
马丁·恩德

@MartinEnder好吧,这么想,但绝不会伤害到问。在那种情况下,我的190字节答案仍然存在。即使一年前我回答了一半,但一个测试用例还是失败了。刚才再次遇到了这个问题,并且能够解决我的答案中的错误。
凯文·克鲁伊森

Answers:


7

JavaScript(ES6),84 78字节

感谢尼尔节省了6个字节

(a,b,c,d,x=a>c?a-c:c-a,y=b>d?b-d:d-b,z=x>y?x:y)=>y+z+(x+z&1?a+b+(b>d)&1||-1:0)

测试用例

初始递归解决方案100 88 81

ETHproductions节省了12个
字节Neil节省了7个字节

f=(a,b,c,d,e=b==d|a+b+(b>d)&1)=>a-c|b-d&&f(e?a+1-2*(a>c):a,e?b:b+1-2*(b>d),c,d)+1

怎么运行的

尽管它本质上仍适用于当前版本,但以下说明更具体地涉及初始版本:

f=(a,b,c,d)=>b-d?a+b+(b>d)&1?f(a+1-2*(a>c),b,c,d)+1:f(a,b+1-2*(b>d),c,d)+1:Math.abs(a-c)

(x0,y)(x1,y)是微不足道的,因为我们可以从源三角形一直到目标三角形一直穿过横向边缘。在这种情况下,曼哈顿距离为| x0-x1 |

棘手的部分是垂直步骤。要从y0行转到y1行,我们必须考虑以下两个参数:

  • 当前三角形的方向
  • 无论Y0是小于或大于Y1

三角形的方向由x + y的奇偶性给出:

  • 如果是偶数,则三角形朝上
  • 如果很奇怪,三角形就是向下的

我们可以从一个向上的三角形向下移动(当y0 <y1时有用),从一个向下的三角形向上移动(当y0> y1时有用)。

通过将三角形的方向与y0y1之间的比较相结合,我们得到公式x + y0 +(y0> y1?1:0),即使我们可以朝所需的方向前进,结果也是奇数。

如果我们不能直接到达下一行,我们首先需要通过更新x获得正确的对齐方式:

  • 如果X尚未等于X1,我们一定要在正确的方向前进,所以我们增加它,如果X小于X1,我们递减,如果X大于X1
  • 如果x已经等于x1,我们可以增加或减少它

测试用例


那是...很多非常小的数学运算...但是您不能n完全不跳过变量,而是在每次迭代的结果中加1吗?(我认为是90个字符
ETHproductions'Apr 4'17

@ETHproductions老实说,我没有认真打高尔夫球就发布了它。但这绝对是第一件事。谢谢!
Arnauld

1
另外,我认为操作符优先级&意味着您可以a+b+(b>d)&1保存2个字节
ETHproductions'Apr4

降至81,我认为:f=(a,b,c,d,e=b==d|a+b+(b>d)&1)=>a-c|b-d&&f(e?a+1-2*(a>c):a,e?b:b+1-2*(b>d),c,d)+1
Neil

我认为可能可以使用一些巧妙的方法节省另一个字节。
尼尔

5

Python 2,74个字节

lambda x,y,X,Y:abs(y-Y)+max(x-X,X-x,abs(y-Y)+((x+y+X+Y)%-2)**(x^y^(Y>=y)))

1
你能不能,请解释一下这个部分:**(x^y^(Y>=y))
Dead Possum'4

1
@DeadPossum垂直移动距离1可以进行1或3个移动;仅查看奇偶校验是无法分辨的,因此您必须比较y值。
feersum

2

批处理,99字节

@cmd/cset/a"x=%3-%1,x*=x>>31|1,y=%4-%2,w=y>>31,y*=w|1,z=x+(y+x&1)*(-(%1+%2+w&1)|1)-y,z*=z>>31,x+y+z

说明:仅水平运动仅包含绝对的x坐标差。对于足够大的x,垂直运动每个绝对y坐标差仅需增加一个步骤,而对于较小的x,每个两个y坐标差则需额外增加四个步骤,对于奇数差则需要增加一或三个步骤。计算为每个差异两个步骤加上一个校正因子。校正后的两个步骤中的较大者和绝对差之和即为结果,尽管这本身是通过校正后的绝对y坐标差和添加到未校正的绝对y坐标差中的绝对x坐标距离中的较大者来计算的。

  • @cmd/cset/a" -评估以逗号分隔的表达式并打印最后一个
  • x=%3-%1,x*=x>>31|1x=|x2x1|
  • y=%4-%2,w=y>>31,y*=w|1w=y1>y2y=|y2y1|
  • z=x+(y+x&1)*(-(%1+%2+w&1)|1)-yc=(y+(xmod2))(12((x1+y1+w)mod2)),z=x+cy
  • z*=z>>31,x+y+z计算max(x,yc)+y=x+ymin(0,x+cy)

2

果冻,24字节

⁴<³¬Ḋ;³S
SḂN*¢+ḊḤ$
ạµS»Ç

在线尝试!

让我们将输入称为。我从费瑟姆的公式中得出结论:(x,y),(X,Y)

d=|yY|+max(|xX|,|yY|+((x+y+X+Y)mod2)xy(Yy))=|yY|+max(|xX|,|yY|+[(|xX|+|yY|mod2)]x+y+(Yy))=max(|xX|+|yY|,2|yY|+[(|xX|+|yY|mod2)](Yy)+x+y).

第一行计算公式中的指数。¢=(Yy)+x+y

最后一行首先计算,然后计算和的最大值,其中是中间行的函数。L=[|xX|,|yY|]sum(L)f(L)f

给定,中线计算,将其取至第次幂,然后加。L=[a,b]((a+b)mod2)¢2b


2

球拍/方案,214字节

(define(f x y X Y)(let m((p x)(q y)(c 0))
(let((k(+ c 1))(d(- Y q)))
(cond((= 0(- X p)d)c)
((and(> d 0)(even?(+ p q)))(m p(+ q 1)k))
((and(< d 0)(odd?(+ p q)))(m p(- q 1)k))
((< p X)(m(+ p 1)q k))
(else(m(- p 1)q k))))))

2

05AB1E,24字节

我的Pyth答案的端口号,该答案又使用了与feersum的Python答案大致相同的方法。将输入作为坐标对列表。修复了+1字节的错误,然后修复了+1的另一个错误,但是对于所有测试用例都产生了正确的结果...(x1,x2),(y1,y2)

ÆÄ`©I˜OÉ(IøнOIθD{Q+m+M®+

在线尝试!

分解

?I?OÉ(IøOOIθD{Q + m +M®+完整程序。I代表评估的输入。
byÄ通过减法减少对,取绝对值。
  `©将它们分别转储到堆栈中并存储第二个
                            一,| y1-y2 | 在寄存器C中
    I〜O将扁平化输入的总和压入堆栈。
       É(采取对等并否定它。
         按[x1,y1]。
            O取x1 + y1(求和)。
             IθD{Q然后检查第二对是否已排序(y1≤y2)。
                  +并用x1 + y1求和。
                   m求幂。将奇偶校验推到**结果之上。
                    +然后加上第二个绝对差。
                     M®+结果,将最大的数字压入堆栈
                            加上存储在寄存器C中的值。

我不确定100%,但是您不能将更©改为D并删除®吗?这似乎适用于您TIO中当前的情况,但是我不确定对于每种情况它是否遵循相同的路径。
凯文·克鲁伊森

1
@KevinCruijssen 编辑:不,因为M的行为会受到此影响。失败[[0, 127], [0, 0]]
Xcoder先生,18年

2

Python 2中74个 72 71字节

lambda c,a,d,b:abs(a-b)+abs(a+(-c-a)/2-b-(-d-b)/2)+abs((c+a)/2-(d+b)/2)

在线尝试!链接包括测试用例。编辑:由于@JoKing,节省了2个字节。感谢@ Mr.Xcoder,进一步节省了字节。基于以下公式,我在此问题中找到了:

|aibi|+|(aiaj2)(bibj2)|+|aj+12bj+12|

坐标系在三种方面有所不同。交换了坐标(这解释了我有点奇怪的参数名称顺序),将坐标倾斜为而不是(这说明了两个加法),并且链接的问题中的坐标使用了劣质的1索引。由于我们采取差异化措施,因此大部分时间都将其抵消,而剩下的就是:12090

|aibi|+|(aiaj+12)(bibj+12)|+|aj2bj2|

然后可以通过注意。aj+12=aj2


您可以通过删除换行符使它成为一个班轮
乔金

1
lambda c,a,d,b:abs(a-b)+abs(a+-(c+a)/2-b--(d+b)/2)+abs((c+a)/2-(d+b)/2)应该保存3个字节。
Xcoder先生

1

Pyth31 28字节

使用与feersum的Python answer中大致相同的方法。将输入作为坐标对列表。修复了-1字节的错误。(x1,x2),(y1,y2)

+eKaMQg#hK+eK^%ssQ_2+shCQSIe

在这里尝试!尝试测试套件!

分解

+ eKaMQg#hK + eK ^%ssQ_2xxFhCQSIe完整程序。Q = eval(输入())。
  KaMQ将差异[| x1-x2 |,| y1-y2 |]存储在K中。
 e检索后者(| y1-y2 |)。
+ g#并将其添加到以下最大值之间:
        hK-K的头(| x1-x2 |)
          +-和添加结果:
           eK K的结尾(| y1-y2 |)。
             ^-求幂的结果:
              %ssQ_2展平的Q的和,取模-2。
                                        如果x1 + x2 + y1 + y2为奇数,则得出-1,否则为0。
                    xxFhCQSIe-通过此表达式的结果:
                       hCQ转置Q并得到水头(x1,y1)。
                     xF按位异或。
                          并检查列表[y1,y2]是否已排序。
                    x之后,将结果乘以布尔值(0/1)。

1

05AB1E,16个字节

使用Neil答案的修改版本,针对05AB1E等基于堆栈的语言进行了优化。将输入作为两对坐标与STDIN换行。最初,我将其与其他05AB1E答案合并,但随后决定将其单独发布,因为它非常非常不同。(x1,x2),(y1,y2)

+D(‚2÷Æ`²Æ©+®)ÄO

在线尝试!尝试测试套件! (使用的是经过稍微修改的代码版本(®而不是²),由Kevin Cruijssen提供


好答案!不是高尔夫,但是当你改变©+®,以DŠ+更容易建立一个测试套件。;)这是测试套件,所有测试用例确实都在成功(忽略混乱的标头; p)。
凯文·克鲁伊森

@KevinCruijssen我有该版本作为替代版本,但我没想到我可以编写一个测试套件...谢谢,我将其添加
Xcoder先生,18年

1
@KevinCruijssen我打了另外两个(非常明显的……!)字节,成功打破了测试套件的兼容性,所以我将它保持原样:P顺便说一下,谢谢你的编辑。
Xcoder先生18年


1

爪哇8,157个 190 188 144 142 141 127字节

(a,b,x,y)->{int r=0,c=1,z=1;for(;(c|z)!=0;r--){c=x-a;z=y-b;if((z<0?-z:z)<(c<0?-c:c)|a%2!=b%2?z<0:z>0)b+=z<0?-1:1;else a+=c<0?-1:1;}return~r;}

由于错误修复,+ 33字节(157→190)。
-44字节(188→144)将递归方法转换为单个循环方法。
-14个字节感谢@ceilingcat

说明:

在这里尝试。

(a,b,x,y)->{          // Method with four integers as parameter and integer return-type
                      // (a=x1; b=y1; x=x2; y=y2)
  int r=0,            //  Result-integer `r`, starting at 0
      c=1,z=1;        //  Temp integers for the differences, starting at 1 for now
  for(;(c|z)!=0;      //  Loop until both differences are 0
      r--){           //    After every iteration: decrease the result `r` by 1
    c=x-a;            //   Set `c` to x2 minus x1
    z=y-b;            //   Set `z` to y2 minus y1
    if(z*Z            //   If the absolute difference between y2 and y1
       <c*c)          //   is smaller than the absolute difference between x2 and x1
       |a%2!=b%2?     //   OR if the triangle at the current location is facing downwards
         z<0          //       and we have to go upwards,
        :z>0)         //      or it's facing upwards and we have to go downwards
      b+=z<0?-1:1;    //    In/decrease y1 by 1 depending on where we have to go
    else              //   Else:
     a+=c<0?-1:1;}    //    In/decrease x1 by 1 depending on where we have to go
  return~r;           //  Return `-r-1` as result

1
建议z*z<c*c而不是(z<0?-z:z)<(c<0?-c:c)
ceilingcat

@ceilingcat啊,不错。谢谢!
凯文·克鲁伊森
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.