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
3つの引数を取るには:g
ボード表す整数の順序対のリストである、とw
してx
開始と終了の正方形を表すペアを命じました。出力は{b, k, n, r}
、2つの正方形の間の最小移動パスを持つ(それぞれ司教、王、騎士、およびルークを表す)サブセットです。たとえば、3番目のテストケースはによって呼び出されf[{{0, 0}, {1, 1}, {1, 2}, {0, 3}}, {0, 0}, {0, 3}]
、戻ります{k}
。最後の2つのテストケースはそれぞれ{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@#
は、これらの隣接グラフの1つを取得し、その接続コンポーネントを見つけます。これは、頂点のすべてのラインセグメントを特定の方向にグループ化することに対応します(ルークまたはビショップが1つずつ移動する必要がないように)。次にe@t@#
、6行目で、同じ接続されたコンポーネント内の頂点のすべてのペアの間にエッジを配置し、それらFlatten
を1つのグラフにまとめます。したがって、6行目から8行目は、ルークのグラフy@r
と司教のグラフを定義していますy@b
。
最後に、9行目から11行目{b, k, n, r}
で、2つのターゲット頂点間の最短パスを生成する要素を選択します。FindShortestPath
は、ターゲット頂点がグラフに表示されない場合はエラーをスローし、未評価で返します(エッジが発せられない場合に発生します)。そのため、代わりにこれらの場合にh@__ -> 0
戻り0
ます。また、有効な頂点間にパスがない場合、lengthのリストが返される0
ためMin[z~Complement~{0}]
、実際に存在する最小パスの長さを計算し、上記の悪いケースを無視します。