Mathematica 745 681バイト
基本的な考え方は、可能な動きの重み付きグラフを作成することです。重みは、ある場所から次の場所に移動するのにかかる時間です。重みが最小のパスが最も速くなります。
入力数字は、r x c(行x列)の長方形配列に配置され、3つの異なる表現が作用します:(1)r x cグリッドグラフ、各頂点は配列内のセルに対応、(2) (r c)by(r c)ある場所(グリッドグラフ)から別の場所に移動するのにかかる時間(2、3、または11分)に対応する重みを保持する重み付き隣接行列、および(3)有向、マトリックスから作成された重み付き隣接グラフ。
グリッドグラフは、各セルからどのセル(つまり頂点)に到達できるかを判断するのに役立ちます。隣接セルは特定のセルの右、左、上、または下だけではないため、「到達可能」です。また、その値は、近隣から1単位の距離内にある必要があります(たとえば、3は近隣の5または1に接続しません)。頂点a
が頂点に接続されていない場合b
、隣接行列セル{a、b}および{b、a}の値は∞になります。したがって、重み付き隣接グラフには、aからbへのエッジもbからaへのエッジもありません。
重み付き隣接グラフはGraphDistance
、頂点間の最短距離()および最短ルートを決定するのに役立ちます。最適なパスは1で始まり、各ピークに触れて、1に戻る必要があります。この場合、「最短ルート」は必ずしも移動が最も少ないルートではありません。これは、エッジの重みで測定された、全体の時間が最も短いものです。
ゴルフ
o=Sequence;v[a_<->b_,z_]:=(m_~u~q_:={Quotient[m-1,q[[2]]]+1,1+Mod[m-1, q[[2]]]};j=z[[o@@u[a,i=Dimensions@z]]];k=z[[o@@u[b,i]]];Which[j==k,{{a,b}->3,{b,a}->3},j==k-1,{{a,b}->11,{b,a}->2},j==k+1,{{a,b}->2,{b,a}->11},2<4,{{a,b}->∞, {b, a}->∞}]);w@e_:=Module[{d,x,l,y},x=Map[ToExpression,Characters/@Drop[StringSplit@e,2],{2}];d_~l~c_:=d[[2]](c[[1]]-1)+c[[2]];g_~y~p_:=(Min[Plus@@(GraphDistance[g,#,#2]&@@@#)&/@(Partition[#,2,1]&/@({1,o@@#,1}&/@Permutations@p))]);y[WeightedAdjacencyGraph[ReplacePart[ConstantArray[∞,{t=Times@@(d=Dimensions@x),t}],Flatten[#~v~x &/@Union@Flatten[EdgeList[GridGraph@Reverse@d,#<->_]&/@Range@(Times@@d),1],1]]], l[Dimensions@x, #] & /@ Position[x, Max@x]]
長くて読みやすい形式
(*determines a weight (number of minutes) to go from vertex a to b and from b to a*)
weight[a_ <-> b_, dat_]:=
Module[{cellA,cellB,dim,valA,valB,vertexToCell},
(*Convert graph vertex index to cell location*)
vertexToCell[m_,dimen_]:={Quotient[m-1,dim[[2]]]+1,1+Mod[m-1,dimen[[2]]]};
dim=Dimensions[dat];
cellA = vertexToCell[a,dim];
cellB = vertexToCell[b,dim];
valA=dat[[Sequence@@cellA]];
valB=dat[[Sequence@@cellB]];
Which[
valA==valB,{{a,b}-> 3,{b,a}-> 3},
valA==valB-1,{{a,b}-> 11,{b,a}-> 2},
valA==valB+1,{{a,b}-> 2,{b,a}-> 11},
2<4,{{a,b}->∞,{b,a}->∞}]];
(* weights[] determines the edge weights (times to get from one position to the next), makes a graph and infers the shortest distance
from vertex 1 to each peak and back. It tries out all permutations of peaks and
selects the shortest one. Finally, it returns the length (in minutes) of the shortest trip. *)
weights[str_]:=
Module[{d,dat,neighbors,cellToVertex,peaks,z,gd},
dat=Map[ToExpression,Characters/@Drop[StringSplit[str],2],{2}];
cellToVertex[dim_,cell_]:=dim[[2]] (cell[[1]]-1)+cell[[2]];
peaks[dat_]:= cellToVertex[Dimensions[dat],#]&/@Position[dat,peak =Max[dat]];
(* to which cells should each cell be compared? neighbors[] is a function defined within weights[]. It returns a graph, g, from which graph distances will be derived in the function gd[] *)
neighbors[dim_]:=
Union@Flatten[EdgeList[GridGraph[Reverse@dim],#<->_]&/@Range@(Times@@dim),1];
d=Dimensions[dat];
m=ReplacePart[ConstantArray[∞,{t=Times@@d,t}],
(*substitutions=*)
Flatten[weight[#,dat]&/@neighbors[d],1]];
g=WeightedAdjacencyGraph[m,VertexLabels->"Name",ImageSize->Full,GraphLayout->"SpringEmbedding"];
(* finds shortest path. gd[] is also defined within weights[] *)
gd[g3_,ps_]:=
Module[{lists,pairs},
pairs=Partition[#,2,1]&/@({1,Sequence@@#,1}&/@Permutations@ps);
Min[Plus@@(GraphDistance[g3,#,#2]&@@@#)&/@pairs]];
gd[g,peaks[dat]]]
テスト
weights["4 5
32445
33434
21153
12343"]
96。
weights@"2 7
6787778
5777679"
75。
weights@"3 4
1132
2221
1230"
51。
説明
次の入力の2〜5行目を考えてください
"4 5
32445
33434
21153
12343"
4行5列の配列を表すもの:
ここで、各頂点は入力配列の数字に対応します。3は頂点1、2は頂点2、4は頂点3、もう4は頂点4、5は頂点5などです。グリッドグラフは大まかなものです目指しているグラフの近似。無向です。さらに、エッジの一部は使用できなくなります。(覚えておいてください:現在の位置から上下に1単位以上の位置から別の位置に移動することはできません。)しかし、グリッドグラフを使用すると、選択した頂点の隣にある頂点を簡単に見つけることができます。これにより、最初の例(4 x 5グリッド)で考慮する必要があるエッジの数が400(20 * 20)から62(31 * 2はグリッドグラフのエッジの数)に減少します。同じ例では、動作するエッジは48のみです。14はそうではありません。
次の20 x 20の重み付き隣接行列は、グリッドグラフからのすべての頂点のペア間の距離を表します。
割り当てる番号を決定するキーコードは次のとおりです。
Which[
valA==valB,{{a,b}-> 3,{b,a}-> 3},
valA==valB-1,{{a,b}-> 11,{b,a}-> 2},
valA==valB+1,{{a,b}-> 2,{b,a}-> 11},
2<4,{{a,b}->∞,{b,a}->∞}]
セル{1,2}-ワンインデクシング-には、頂点1から頂点2への移動が下り坂のため、値2が含まれています。セル{2,1}には11が含まれます。これは、頂点2から頂点1への移動が上り坂だからです。セル{1,6}および{6,1}の3は、動きが上でも下でもないことを示します。セル{1,1}はそれ自体に接続されていないため、∞を含んでいます。
次のグラフは、上記の入力の基礎となる構造を示しています。色付きの矢印は、頂点1からピーク(5および14)に戻り、1に戻る最適なパスを示しています。青い矢印は、同じレベル(3分)の動きに対応しています。赤い矢印は上昇(11分)を意味し、緑の矢印は下降(2分)を示します。
頂点1(セル{1,1}から2つのピークまで、そして頂点1に戻るパス)
3 + 3 + 11 + 3 + 3 + 11 + 2 + 2 + 3 + 11 + 11 + 2 + 2 + 2 + 2 + 11 + 11 + 3
96