2つのノードの間の環状グラフで最長のパスを見つけるにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/2679081

  •  30-09-2019
  •  | 
  •  

質問

私はすでに投稿されたほとんどの質問を解決しました ここ, 、最長のパスを除くすべて。私は最長のパスに関するウィキペディアの記事を読んだことがありますが、グラフが非環境である場合、それは私のものではない場合、簡単な問題のようです。

それではどうすれば問題を解決できますか?可能なすべてのパスをチェックすることにより、ブルートフォース?どうすればそれを始めますか?

〜18000のグラフで多くのことをするだろうと私は知っています。しかし、とにかくそれを開発したいだけです。プロジェクトに必要なので、実行時間がわずか1〜2秒である小規模なグラフでテストしてインストラクターに表示します。

少なくとも私は必要なすべてのタスクを行い、それが機能するという概念実証を実行していますが、周期的なグラフにはより良い方法はありません。しかし、私はこれらすべてのパスをチェックし始める場所を知らない...

役に立ちましたか?

解決

解決策は、それを強制的に強制的にすることです。あなたはそれをスピードアップするためにいくつかの最適化を行うことができます、いくつかは些細なものであり、いくつかは非常に複雑です。デスクトップコンピューターで18,000ノードのために十分に速く動作させることができるとは思わないでしょう。ただし、Bruteforceの仕組みは次のとおりです。

ノート: Dijkstraと他の最短パスアルゴリズムのいずれも、正確な答えに興味がある場合、この問題には機能しません。

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<int> ポインターを保存してランダムにアクセスできるようにするために、リストをリストします。たとえば、保持できます next[i] = next child of node i in its adjacency list それに応じて更新します。あなたはいくつかのエッジケースを持っているかもしれないし、異なる必要があるかもしれない end: 状況:既に訪問したノードにアクセスしたときに発生する通常のものとその場合、ポインターをリセットする必要はありません。これを避けるために、スタックに何かを押すことに決める前に、訪問した状態を動かしてください。

気にするべきではないと言った理由をご覧ください。 :)

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top