Mathematica,326 325字节
感谢masterX224指出节省了一个字节!
f[g_,w_,x_]:=(c={{1,1},{-1,1}};s=c.c/2;e=#<->#2&@@@#&;j=Join;h=FindShortestPath;t=#~Tuples~2&;a@d_:=e@Select[t@g,#-#2&@@#==d&];y@k=j@@(a/@j[s,c]);y@n=j@@(a/@{{1,2},{2,1},{-2,1},{-1,2}});v=Flatten[e@t@#&/@ConnectedComponents@a@#&/@#]&;y@r=v@s;y@b=v@c;Pick[p={b,k,n,r},z=Length[h[y@#,w,x]/.h@__->0]&/@p,Min[z~Complement~{0}]]);
定义一个函数f
取三个参数:g
是有序对占板整数的列表,w
并x
下令代表开始和结束的广场对。输出是{b, k, n, r}
(分别代表Bishop,King,Knight和Rook)的子集,它们在两个方块之间具有最小移动路径。例如,第三个测试用例由调用f[{{0, 0}, {1, 1}, {1, 2}, {0, 3}}, {0, 0}, {0, 3}]
并返回{k}
;最后两个测试用例分别返回{k, n}
和{}
。
该策略是将木板的正方形转换为图形的顶点,然后由内置的图形例程将图形的顶点确定为各边的移动。
代码的用户更友好版本:
1 f[g_, w_, x_] := ( c = {{1, 1}, {-1, 1}}; s = c.c/2;
2 e = # <-> #2 & @@@ # &; j = Join; h = FindShortestPath; t = #~Tuples~2 &;
3 a@d_ := e@Select[t@g, # - #2 & @@ # == d &];
4 y@k = j @@ (a /@ j[s, c]);
5 y@n = j @@ (a /@ {{1, 2}, {2, 1}, {-2, 1}, {-1, 2}});
6 v = Flatten[e@t@# & /@
7 ConnectedComponents@a@# & /@ #] &;
8 y@r = v@s; y@b = v@c;
9 Pick[p = {b, k, n, r},
10 z = Length[h[y@#, w, x] /. h@__ -> 0] & /@ p,
11 Min[z~Complement~{0}]]
12 );
在第3行中,Select[g~Tuples~2, # - #2 & @@ # == d
找到所有差值是向量的顶点的有序对d
。e
然后将每个这样的有序对转换为无向图边。因此a
,一个函数会在所有以固定向量相差的顶点之间创建边。
这足以来定义,在管路4和5,王的曲线图y@k
(其取得由矢量生成边缘的并集{1, 1}
,{-1, 1}
,{0, 1}
,和{-1, 0}
)和骑士的曲线图y@n
(其不具有相同的{1, 2}
,{2, 1}
,{-2, 1}
,和{-1, 2}
)。
在第7行中,ConnectedComponents@a@#
获取这些邻居图之一,然后找到其连接的组件;这相当于将给定方向上的所有顶点线段分组(这样一来,车子或主教就不必一一穿过它们了)。然后,e@t@#
在第6行中,将边线放在同一连接组件中的每对顶点之间,然后将其Flatten
编辑为单个图形。因此,第6至8行定义了车队图y@r
和主教图y@b
。
最后,第9到11行选择{b, k, n, r}
在两个目标顶点之间产生最短路径的元素。FindShortestPath
如果目标顶点未出现在图形中,将抛出错误并返回未评估的值(如果没有顶点出现,则发生),因此我们在这些情况下使用h@__ -> 0
return 0
来代替。有效顶点之间缺少路径会返回一个length列表0
,因此可以Min[z~Complement~{0}]
计算出实际存在的最小路径的长度,而无需考虑上述不良情况。