Python 2 208 205 200字节
A=lambda n:n and A(~-n/3)+[-n%3]or[]
f=lambda x,y:f(A(x),A(y))if x<[]else["SSNEW"[m::3]for m in
y[len(x):]]if x==y[:len(x)]else min([["NNSWE"[m::3]]+f(x[:~x[::-1].index(m)],y)for
m in set(x)],key=len)
函数f
带有一对节点号,并返回最短路径作为字符串列表。
说明
我们从对三角形采用不同的寻址方案开始;每个三角形的地址是一个字符串,定义如下:
本质上,每个三角形的地址编码从中心三角形到它的(最短)路径。我们的程序要做的第一件事是将输入的三角形数字转换为相应的地址。
单击图像查看大图。
可以根据地址轻松确定每个三角形处的可能移动:
要移动到北部,西南部和东南部的孩子,我们简单地追加0
,1
和2
分别的地址。
要移动到南部,东北部和西北部的祖先,我们找到的最后一个(最右边)的发生0
,1
和2
分别,和微调地址到左边的吧。如果地址中没有0
,1
或2
,则相应的祖先不存在。例如,要移至112
(即其父级)的西北祖先,我们发现2
in 的最后一次出现(即112
最后一个字符),并在其左侧修剪地址,从而得到11
; 要移至东北祖先,我们找到1
in 的最后一个出现112
,它是第二个字符,并在其左侧修整地址,从而给我们1
;但是,112
由于没有祖先,所以没有南祖先0
在其地址中。
需要注意的几件事情讲述了一对地址,x
并且y
:
如果x
是的初始子串y
,则y
是的后代x
,因此从x
到的最短路径y
简单地遵循x
和之间的每个三角形的对应子代y
。换句话说,我们可以相互替换0
,1
以及2
在y[len(x):]
用N
,SW
和SE
分别。
否则,i
设为x
和之间的第一个不匹配项的索引y
。有没有从路径x
到y
不通过x[:i]
(其是相同的y[:i]
),即,所述第一共同祖先x
和y
。因此,从x
到的任何路径都y
必须到达x[:i]
,或其祖先之一,我们称这个三角形z
,然后继续y
。若要从到货x
到z
,我们遵循祖先如上所述。从z
到的最短路径y
由上一个项目符号点给出。
如果x
是的初始子串y
,则上面的第一个项目符号点很容易给出从x
到的最短路径y
。否则,我们让j
是最小的最后出现的指标0
,1
以及2
在x
。如果j
大于或等于,之间的第一失配的索引x
和y
,i
我们简单地添加相应的移动(S
,NE
,或NW
,分别地)的路径,修剪x
到左的j
,并继续。如果j
小于i
,事情会变得更加棘手,因为从那时起,我们可能会直接y
上升到共同祖先x[:j]
并一直下降到y
或者我们也许能够去一个不同的共同祖先x
,并y
认为更接近于y
由上升到一个不同的祖先x
到右侧i
,并从那里得到y
更快。例如,要从1222
到达1
,最短的路径是首先上升到中心三角形(其地址是空字符串),然后下降到1
,即,第一步将我们带到不匹配点的左侧。但是,要从1222
到达12
,最短的路径是先上升到122
,然后再上升到12
,即,第一个举动将我们带到错配点的右边。
那么,我们如何找到最短的路径?“官方”程序使用暴力破解方法,只要x
不是的初始子串,就尝试所有可能的移动到任何祖先y
。听起来还不错!它在一两秒钟之内就解决了所有测试用例。
但是话又说回来,我们可以做得更好:如果不匹配点的左边有多个直接可联系的祖先,我们只需要测试最右边的一个,而如果不匹配的祖先不止一个,在不匹配点的右边,我们只需要测试最左边的那个。这将产生一个线性时间算法,该算法的长度x
(即源三角形的深度,或与源三角形数量的对数成正比的时间)可以放大更大的测试用例。以下程序至少在本质上实现了该算法-由于打高尔夫球,其复杂性实际上比线性复杂,但仍然非常快。
Python 2 271 266 261字节
def f(x,y):
exec"g=f;f=[]\nwhile y:f=[-y%3]+f;y=~-y/3\ny=x;"*2;G=["SSNEW"[n::3]for
n in g];P=G+f;p=[];s=0
while f[s:]:
i=len(f)+~max(map(f[::-1].index,f[s:]));m=["NNSWE"[f[i]::3]]
if f[:i]==g[:i]:P=min(p+m+G[i:],P,key=len);s=i+1
else:p+=m;f=f[:i]
return P
请注意,与较短的版本不同,此版本专门编写为在输入值到其对应地址的转换中不使用递归,以便它可以处理非常大的值而不会导致堆栈溢出。
结果
以下代码段可用于运行任一版本的测试并生成结果:
def test(x, y, length):
path = f(x, y)
print "%10d %10d => %2d: %s" % (x, y, len(path), " ".join(path))
assert len(path) == length
# x y Length
test( 0, 40, 4 )
test( 66, 67, 5 )
test( 30, 2, 2 )
test( 93, 2, 2 )
test( 120, 61, 8 )
test( 1493682877, 0, 4 )
test( 0, 368460408, 18 )
test( 1371432130, 1242824, 17 )
test( 520174, 1675046339, 23 )
test( 312602548, 940907702, 19 )
test( 1238153746, 1371016873, 22 )
test( 547211529, 1386725128, 23 )
test( 1162261466, 1743392199, 38 )
高尔夫版
0 40 => 4: N N N N
66 67 => 5: S SW N N N
30 2 => 2: NE SW
93 2 => 2: NE SW
120 61 => 8: NW NW NW NW N SE SW N
1493682877 0 => 4: S S NW NW
0 368460408 => 18: SW SW N N SW SW SE SW SW N SE N N SW SW N SE SE
1371432130 1242824 => 17: NW NW NE NW N SE SW SW SW SE SE SW N N N N SW
520174 1675046339 => 23: NE NE NE NE SE SE SW SW N SE N SW N SW SE N N N N SE SE SW SW
312602548 940907702 => 19: NE NW S SW N N SW SE SE SE SW SE N N SW SE SE SE SW
1238153746 1371016873 => 22: NE NE NE SE N N SW N N SW N SE SE SW N SW N N SE N SE N
547211529 1386725128 => 23: S S S S NW N N SE N SW N SE SW SE SW N SE SE N SE SW SW N
1162261466 1743392199 => 38: NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE
高效版
0 40 => 4: N N N N
66 67 => 5: S SW N N N
30 2 => 2: NW NW
93 2 => 2: NE SW
120 61 => 8: NW NW NW NW N SE SW N
1493682877 0 => 4: NE S NW NW
0 368460408 => 18: SW SW N N SW SW SE SW SW N SE N N SW SW N SE SE
1371432130 1242824 => 17: NW NW NE NW N SE SW SW SW SE SE SW N N N N SW
520174 1675046339 => 23: NE NW NE NE SE SE SW SW N SE N SW N SW SE N N N N SE SE SW SW
312602548 940907702 => 19: NE NW S SW N N SW SE SE SE SW SE N N SW SE SE SE SW
1238153746 1371016873 => 22: NE NE NE SE N N SW N N SW N SE SE SW N SW N N SE N SE N
547211529 1386725128 => 23: S S S S NW N N SE N SW N SE SW SE SW N SE SE N SE SW SW N
1162261466 1743392199 => 38: NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE