Mathematica 745681字节
基本思想是制作可能动作的加权图。权重是从一个位置移动到另一个位置所花费的时间。重量最小的路径将是最快的。
将输入数字放置在r x c(行列)矩形数组中,然后使用三个不同的表示形式:(1)r x c网格图,其中每个顶点对应于数组中的一个单元,(2) (r c)乘以(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}-在一个索引中-包含值2,因为从顶点1到顶点2的移动是下坡的。单元格{2,1}包含11,因为从顶点2到顶点1的移动是艰难的。单元格{1,6}和{6,1}中的3表示移动既不向上也不向下。单元格{1,1}包含∞,因为它未与自身连接。
下图显示了以上输入的基础结构。彩色箭头表示从顶点1到峰值(在5和14)并返回到1的最佳路径。蓝色箭头表示在相同水平(3分钟)的移动;而箭头表示在同一水平上的移动。红色箭头表示上升(11分钟),绿色箭头表示下降(2分钟)。
从顶点1(像元{1,1}到两个峰再回到顶点1的路径):
3 + 3 + 11 + 3 + 3 + 11 + 2 + 2 + 3 + 11 + 11 + 2 + 2 + 2 + 2 + 11 + 11 + 3
96