Mathematica 745 681 байт
Основная идея - составить взвешенный график возможных ходов. Вес - это время, необходимое для перемещения из одного места в другое. Путь с наименьшим весом будет самым быстрым.
Входные цифры помещаются в прямоугольный массив r by c (строки по столбцам), а затем в игру вступают три различных представления: (1) граф сетки r by 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. В этом случае «кратчайший маршрут» не обязательно тот, который имеет наименьшее количество ходов. Это время с наименьшим общим временем, измеренным в весах ребер.
Golfed
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 на 5) с 400 (20 * 20) до 62 (31 * 2 - количество ребер в графе сетки). В том же примере только 48 ребер являются действующими; 14 нет.
Следующая взвешенная матрица смежности 20 на 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 идет в гору. 3 в ячейках {1,6} и {6,1} означают, что движение не идет ни вверх, ни вниз. Ячейка {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