web-dev-qa-db-ja.com

オイラーパスを見つけるアルゴリズムを探しています

グラフでオイラーパスを見つけるアルゴリズムを探しています。

数週間前に良いものを見てきましたが、今は見つかりません。タグ付けエッジがあったことを覚えています。偶数/奇数の接続があります...

同様のシンプルで簡単なアルゴリズムを知っていますか?

13
user2489034

Graph-Magics.com から、無向グラフの場合、これはツアーを逆の順序で、つまり終了頂点から開始頂点へと提供します。

  1. 空のスタックと空の回路(オイラーパス)から始めます。
    • すべての頂点に次数がある場合:それらのいずれかを選択します。これが現在の頂点になります。
    • 次数が奇数の頂点がちょうど2つある場合は、そのうちの1つを選択します。これが現在の頂点になります。
    • そうでない場合、オイラー回路またはパスは存在しません。

現在の頂点に隣接がなくなり、スタックが空になるまで、手順2を繰り返します。

  1. 現在の頂点に隣接がない場合:
    • 回路に追加し、
    • スタックから最後の頂点を削除し、現在の頂点として設定します。

さもないと:

  • 頂点をスタックに追加し、
  • その隣接のいずれかを取得し、選択した隣接とその頂点の間のエッジを削除し、その隣接を現在の頂点として設定します。
20
MJW

私はどの言語のコードも持っていませんが、アルゴリズム、検索方法はわかっているので、ここで記述します。

N個のノードを持つグラフがあるとします。このノードに接続されているエッジのノード数を次数と呼びます。最初に、各ノードの合計次数は「ハンドシェイク問題」に応じて均一になると言う必要があります。

次に、ノードsからノードfまでのオイラーパスpがあるとします。次に、stとtとは異なる各ノードについて、そのノードに入るたびに、離れる必要があります(離れない場合、最後のfノードに到達しません)。したがって、これらのノードの次数は均一になります、およびsとfの場合、次数が異なる場合は奇数になります。これは、最初にsを離れた後、各Enterの後にsノードを離れたため、1 + 2 * n次数になります。nは数値です。時々私達は再び訪れました。 fも同様です。したがって、オイラーパスが存在する場合は、次数が奇数の2つのノードがあるはずです。そして、オイラー円がある場合、各ノードの次数は均一でなければなりません。これが当てはまる場合、どのノードをsとして選択してもかまいません。円もsで終了します。

今問題はオイラー円/パスを取得する方法です。ここでは、グラフで「ブリッジ」を定義する必要があります。ブリッジは特定のプロパティを持つエッジです。そのエッジを削除すると、残りのグラフでコンポーネントの数が1つ増えます。つまり、bridgeはEdgeであり、グラフ内の2つのコンポーネントの唯一の接続Edgeです。

ブリッジとは何かを知っているので、アルゴリズムを定義できます。次数が偶数の正確に2つのノードが存在する場合:1)それらの1つから開始し、現在のノードに接続されているエッジを選択することにより、次のノードに進みます。 2)ブリッジと非ブリッジの間のエッジを選択する場合は、常に非ブリッジを選択する必要があります。 3)ノードnonebridge Edgeが残っている場合のみ、任意のブリッジを選択できます。

奇数次のノードがない場合は、任意のノードから始めて、これら3つのルールに従うことができます。

これが常に機能するアルゴリズム全体です。ここにもいくつかの便利なリンクがあります。

https://www.math.ku.edu/~jmartin/courses/math105-F11/Lectures/chapter5-part2.pdfhttp://www.graph-magics.com /articles/euler.php

3
Mamuka

Hierholzerのアルゴリズムは、有向グラフでオイラーパスを見つけるより良い方法です。

http://stones333.blogspot.com/2013/11/find-eulerian-path-in-directed-graph.html

コードとテストケースがあります。

3
stones333

グラフに奇数次の頂点が2つある場合、オイラーパスが存在します。これらは実際にはオイラーパスの終点です。

したがって、奇数の頂点を見つけ、DFSを使用してグラフのトラバースを開始できます。

頂点から残っているエッジがない場合は、すべてのエッジにアクセスしたかどうかを確認します。

実際のオイラーパスを格納するには、パスの以前の頂点を格納する先行配列を保持できます。

0
Aravind

これが私の解決策です。「スタックが空です」という例外が発生し、実際に修正する時間がないため、最終的にブロックして印刷しました。これが誰かに役立つことを願っています!

public void EulerTour()
    {
        GetInput(); //gets the adjency matrix

        int start = NodeList[0]; //start from any vertex, i choose 0
        tempPath.Push(NodeList[0]); //temporary path - stack
        try
        {
            while (tempPath.Count != 0) 
            {
                for (int i = 0; i < total; i++)
                {
                    if (adjencyMatrix[start, i] == 'd')
                    {
                        tempPath.Push(NodeList[i]);
                        adjencyMatrix[start, i] = 'n';
                        adjencyMatrix[i, start] = 'n';

                        if (!hasNeighbour((int)tempPath.Peek())) //checks if current node has any neighbour
                        {
                            while (!hasNeigbour((int)tempPath.Peek()))
                            {
                                finalPath.Push(tempPath.Pop());

                            }
                            start = (int)tempPath.Peek();
                        }
                        else
                        {
                            start = i;
                            break;
                        }
                    }
                }
            }
        }
        catch
        {
            Console.WriteLine("Print: ");
        }
        finally
        {
            foreach (object o in finalPath)
            {
                Console.Write(o.ToString() + "---->");
            }
        }     
        Console.ReadKey();            
    }
0
Jure Kljajic