Я уже решил больше всего вопросы, отправленные здесь, все кроме самого длинного пути один. Я прочитал статью Wikipedia о самых длинных путях, и кажется любой легкой проблемой, если график был нециклическим, который мой не.
Как я решаю проблему затем? Грубая сила, путем проверки всех возможных путей? Как я даже начинаю делать это?
Я знаю, что это собирается взять МНОГО на Графике с ~18000. Но я просто хочу разработать его так или иначе, для порождения это требуется для проекта, и я просто протестирую его и покажу его преподавателю на графике меньшего масштаба, где время выполнения является только секундой или два.
По крайней мере, я сделал все требуемые задачи, и у меня есть под управлением подтверждение концепции, что оно работает, но на циклических графиках нет никакого лучшего пути. Но у меня нет подсказки, где начать проверять все эти пути...
Решение состоит в том, чтобы переборить его. Вы можете сделать некоторые оптимизации, чтобы ускорить его, некоторые тривиальны, некоторые очень сложны. Я сомневаюсь, что вы можете заставить его работать достаточно быстро для 18 000 узлов на настольном компьютере, и даже если вы можете, я понятия не имею, как. Однако вот как работает брутфорс.
Примечание: Дейкстра и любой другой алгоритм кратчайшего пути НЕ будут работать для этой задачи, если вы заинтересованы в точном ответе.
Start at a root node *root*
Let D[i] = longest path from node *root* to node i. D[*root*] = 0, and the others are also 0.
void getLongestPath(node, currSum)
{
if node is visited
return;
mark node as visited;
if D[node] < currSum
D[node] = currSum;
for each child i of node do
getLongestPath(i, currSum + EdgeWeight(i, node));
mark node as not visited;
}
Давайте запустим его вручную на этом графике: 1 - 2 (4), 1 - 3 (100), 2 - 3 (5), 3 - 5 (200), 3 - 4 (7), 4 - 5 (1000)
Let the root be 1. We call getLongestPath(1, 0);
2 is marked as visited and getLongestPath(2, 4); is called
D[2] = 0 < currSum = 4 so D[2] = 4.
3 is marked as visited and getLongestPath(3, 4 + 5); is called
D[3] = 0 < currSum = 9 so D[3] = 9.
4 is marked as visited and getLongestPath(4, 9 + 7); is called
D[4] = 0 < currSum = 16 so D[4] = 16.
5 is marked as visited and getLongestPath(5, 16 + 1000); is called
D[5] = 0 < currSum = 1016 so D[5] = 1016.
getLongestPath(3, 1016 + 200); is called, but node 3 is marked as visited, so nothing happens.
Node 5 has no more child nodes, so the function marks 5 as not visited and backtracks to 4. The backtracking will happen until node 1 is hit, which will end up setting D[3] = 100 and updating more nodes.
Вот как это будет выглядеть итеративно (не проверено, просто основная идея):
Let st be a stack, the rest remains unchanged;
void getLongestPath(root)
{
st.push(pair(root, 0));
while st is not empty
{
topStack = st.top();
if topStack.node is visited
goto end;
mark topStack.node as visited;
if D[topStack.node] < topStack.sum
D[topStack.node = topStack.sum;
if topStack.node has a remaining child (*)
st.push(pair(nextchild of topStack.node, topStack.sum + edge cost of topStack.node - nextchild))
end:
mark topStack.node as not visited
st.pop();
}
}
(*) - это небольшая проблема - вы должны сохранить указатель на следующего ребенка для каждого узла,так как он может меняться между различными итерациями цикла while и даже сбрасывать себя (указатель сбрасывает себя, когда вы выбрасываете узел topStack.node
из стека, поэтому обязательно сбросьте его). Это проще всего реализовать в связанных списках, однако вы должны использовать либо списки int[]
, либо списки vector
, чтобы иметь возможность хранить указатели и иметь произвольный доступ, потому что вам это понадобится. Вы можете сохранить, например, next[i] = следующий дочерний узел i в его списке схожести
и обновить его соответствующим образом. У вас могут быть некоторые крайние случаи и может потребоваться различные ситуации end:
: нормальная и та, которая происходит при посещении уже посещенный узел, и в этом случае указатели не нужно сбрасывать. Может быть, сдвиньте посещаемые условия, прежде чем вы решите надавить что-то на стек, чтобы избежать этого.
Понимаете, почему я сказал, что вы не должны беспокоиться? :)