プリムとダイクストラのアルゴリズムの違いは?


91

ダイクストラのアルゴリズムとプリムのアルゴリズムの正確な違いは何ですか?私はプリムがMSTを与えることを知っていますが、ダイクストラによって生成されたツリーもMSTになります。次に、正確な違いは何ですか?


3
ダイクストラです。"ij"はオランダ語の母音(滑走母音)であり、 "j"が子音でない1つの場所です。

22
あなたが質問を得たどんな方法でも。
anuj pradhan 2013年

4
それらの違いを区別する最良の方法は、いくつかのソースコードダイクストラプリムを読むことです。主な違いはここにあります:Prim graph[u][v] < key[v]とDijkstra dist[u]+graph[u][v] < dist[v]です。したがって、これら2つのページのグラフからわかるように、主に 2行のコードが原因で、グラフは異なります。
JW.ZG 2017

回答:


146

Primのアルゴリズムは、グラフの最小スパニングツリーを構築します。これは、グラフ内のすべてのノードを接続するツリーであり、すべてのノードを接続するすべてのツリーの中で総コストが最小になります。ただし、MSTの2つのノード間のパスの長さは、元のグラフの2つのノード間の最短パスではない場合があります。たとえば、MSTは、グラフのノードを物理的に配線して、最小の総コストでノードに電力を供給したい場合に役立ちます。2つのノード間のパスの長さが最適でなくてもかまいません。重要なのは、ノードが接続されているという事実だけだからです。

ダイクストラのアルゴリズムは、あるソースノードから始まる最短パスツリーを構築します。最短パスツリーは、グラフ内のすべてのノードをソースノードに接続するツリーであり、ソースノードからグラフ内の他のノードまでのパスの長さが最小になるというプロパティがあります。これは、たとえば、すべての人が主要な重要なランドマークに到達するのを可能な限り効率的にする道路網を構築したい場合に役立ちます。ただし、最短パスツリーは最小スパニングツリーであるとは限りません。最短パスツリーのエッジのコストの合計は、MSTのコストよりもはるかに大きくなる可能性があります。

もう1つの重要な違いは、アルゴリズムが機能するグラフのタイプに関するものです。MSTの概念はグラフが本質的に無向であると想定しているため、Primのアルゴリズムは無向グラフでのみ機能します。(有向グラフには「最小全域樹」と呼ばれるものがありますが、それらを見つけるアルゴリズムははるかに複雑です)。ダイクストラのアルゴリズムは、最短パスツリーを実際に有向にすることができるので、有向グラフで正常に動作します。さらに、ダイクストラのアルゴリズム負のエッジの重みを含むグラフで必ずしも正しい解をもたらすわけではありませんが、プリムのアルゴリズムはこれを処理できます。

お役に立てれば!


最初の段落は意味がありません。質問は、ダイクストラとプリムの違いは何ですか?ダイクストラがあなたの言ったことではありませんがthe length of a path between **any** two nodes、srcノードとプリムの他のノードの間の距離が最短でなければ最短ではない理由に焦点を当てる必要があります。私は彼がPrimsrcノードに他のノードを要求しているに違いないと思います。なぜプリムの2つのノードについて話しましたか?もちろん、それは最短ではありません。
JW.ZG 2017

1
ダイクストラのアルゴリズムに関する段落の表現を整理して、最短パスツリーはソースノードで発生した最短パスの最小化にすぎないことを明確にしました。私が私の答えを構造化した理由は、アルゴリズムどのように機能してより高いレベルで表示するかではなく、アルゴリズムが見つけたものを説明する方法でした。
templatetypedef

1
最も簡単な説明は、プリムでは開始ノードを指定しないことですが、ダイクストラでは(開始ノードが必要)、指定されたノードから他のすべてのノードへの最短パスを見つける必要があります。stackoverflow.com/a/51605961/6668734を
Deepak Yadav

1
@templatetypedef-あなたが言うとき:「そしてそのようなツリーを構築するコスト(ダイクストラで)は、MSTのコストよりはるかに大きくなる可能性があります。」詳しく説明してもらえますか?
Amelio Vazquez-Reina

1
@ AmelioVazquez-Reinaすみません、あいまいです。つまり、最短パスツリーのエッジの重みの合計は、MSTのエッジの重みの合計よりもはるかに大きくなる可能性があります。
templatetypedef

82

ダイクストラのアルゴリズムはMSTを作成せず、最短経路を見つけます。

このグラフを考えてみましょう

       5     5
  s *-----*-----* t
     \         /
       -------
         9

最短パスは9ですが、MSTは10の別の「パス」です。


2
わかりました...気づくのに良いポイントをクリアしました。今まで私はdijkstraによって生成された出力がMSTになることを検討していましたが、良い例で疑いを解消しました。「kruskal」と言ってMSTを見つけることができれば、あなたが述べたのと同じパスを取得します。ありがとうございました
anuj pradhan 2013年

8
もっと正確に-... The shortest path is 9からsへ。ダイクストラのアルゴリズムによって生成された、sから始まるグラフの重みは14(5 + 9)です。
Bernhard Barker

1
@Dukeling-えっ?ダイクストラのツリー/グラフの重みは無意味です、それは一種のポイントです...
dfb

4
非常に簡潔に示されています!
Ram Narasimhan 14年

1
@dfb:通常、特定の頂点のペア間の最短パスを取得するためにダイクストラのアルゴリズムのみを実行しますが、実際には、すべての頂点にアクセスするまで進むことができ、これにより、テンプレートタイプ定義の答えとして「最短パスツリー」が得られます説明します。
j_random_hacker 14

63

PrimアルゴリズムとDijkstraアルゴリズムは、「relax関数」を除いてほとんど同じです。

堅苦しい:

MST-PRIM (G, w, r) {
    for each key ∈ G.V
        u.key = ∞
        u.parent = NIL
    r.key = 0
    Q = G.V

    while (Q ≠ ø)
        u = Extract-Min(Q)
        for each v ∈ G.Adj[u]
            if (v ∈ Q)
                alt = w(u,v)    <== relax function, Pay attention here
                if alt < v.key
                    v.parent = u
                    v.key = alt
}

ダイクストラ:

Dijkstra (G, w, r) {
    for each key ∈ G.V
        u.key = ∞
        u.parent = NIL
    r.key = 0
    Q = G.V

    while (Q ≠ ø)
        u = Extract-Min(Q)
        for each v ∈ G.Adj[u]
            if (v ∈ Q)
                alt = w(u,v) + u.key  <== relax function, Pay attention here
                if alt < v.key
                    v.parent = u
                    v.key = alt
}

唯一の違いは、リラックス機能である矢印で示されています。

  • 最小全域木を検索するプリムは、すべての頂点をカバーする合計エッジの最小値のみを考慮します。リラックス機能はalt = w(u,v)
  • 最小パス長を検索するダイクストラ。エッジの累積を考慮します。リラックス機能はalt = w(u,v) + u.key

コードレベルでは、もう1つの違いはAPIです。Primにはedges()MSTエッジを返すメソッドがありますが、DijkstraにはdistanceTo(v)pathTo(v)ソースから頂点vへの距離とソースから頂点vへのパスをそれぞれ返す、があります。ここで、sは、ダイクストラを初期化する頂点です。
nethsix

1
当然、任意のソース頂点でPrimを初期化すると、sはの同じ出力を返しますが、edges()異なるsで初期化ダイクストラはdistanceTo(v)、の異なる出力を返しますpathTo(v)
nethsix

プリムは負の重みを許可しますか?はいの場合、これは別の違いです。私はあなたが大きな正のnoを追加することでプリムに負の重みを許可できることを読んだ すべての値をプラスにします。
Akhil Dad 2016

1
私の混乱を解決しました!完璧な答え!!
Dhananjay Sarsonia

ここでは、無向グラフのために処理された頂点を無視する必要があります
Mr AJ

53

Dijsktraのアルゴリズムはノードiからすべてのノードまでの最小距離見つけます(iを指定)ます。したがって、代わりにノードiから最小距離ツリーを取得します。

プリムアルゴリズムは、特定のグラフの最小スパニングツリー取得します。すべてのコストの合計が可能な限り最小であるときに、すべてのノードを接続するツリー。

したがって、ダイクストラを使用すると、選択したノードから他のノードに最小コストで移動できます。プリムではこれを取得できません


最も簡単な説明は、プリムでは開始ノードを指定しないことですが、ダイクストラでは(開始ノードが必要)、指定されたノードから他のすべてのノードへの最短パスを見つける必要があります。stackoverflow.com/a/51605961/6668734を
Deepak Yadav

32

唯一の違いは、Primのアルゴリズムは最小コストエッジを格納するのに対し、Dijkstraのアルゴリズムはソース頂点から現在の頂点までの合計コストを格納することです。

ダイクストラは、コストが最小になるように、ソースノードから宛先ノードへの道を提供します。ただし、プリムのアルゴリズムは、すべてのノードが接続され、総コストが最小になるような最小のスパニングツリーを提供します。

簡単な言葉で:

したがって、複数の都市を結ぶ列車を配備する場合は、プリムのアルゴを使用します。しかし、ある都市から別の都市に移動して時間をできるだけ節約したい場合は、ダイクストラのアルゴリズムを使用します。


24

どちらも、次のようにまったく同じ汎用アルゴリズムを使用して実装できます。

Inputs:
  G: Graph
  s: Starting vertex (any for Prim, source for Dijkstra)
  f: a function that takes vertices u and v, returns a number

Generic(G, s, f)
    Q = Enqueue all V with key = infinity, parent = null
    s.key = 0
    While Q is not empty
        u = dequeue Q
        For each v in adj(u)
            if v is in Q and v.key > f(u,v)
                v.key = f(u,v)
                v.parent = u

プリムの場合はpass f = w(u, v)、ダイクストラの場合はpass f = u.key + w(u, v)です。

もう1つの興味深い点は、上記のGenericは幅優先検索(BFS)も実装できることですが、高価な優先キューは実際には必要ないため、やりすぎです。上記の汎用アルゴリズムをBFSに変換するには、次を渡します。f = u.key + 1するにはすべての重みを1に強制するのと同じをます(つまり、BFSは、ポイントAからBに移動するために必要なエッジの最小数を提供します)。

直感

上記の一般的なアルゴリズムについて考える良い方法の1つは次のとおりです。まず、2つのバケットAとBから始めます。最初に、すべての頂点をBに配置して、バケットAを空にします。次に、1つの頂点をBからAに移動します。次に、Aの頂点からBの頂点に交差するすべてのエッジを確認します。これらの交差エッジからいくつかの基準を使用して1つのエッジを選択し、対応する頂点をBからA. Bが空になるまで、このプロセスを繰り返します。

このアイデアを実装する強力な方法は、Bに渡るAの頂点のエッジの優先度キューを維持することです。明らかに、グラフがスパースでない場合、これは面倒です。では問題は、代わりに頂点の優先キューを維持できるでしょうか?実際、これは最終的にBからどの頂点を選択するかを決定することで可能になります。

歴史的背景

興味深いのは、両方のアルゴリズムの背後にある手法の一般的なバージョンが、電子コンピューターがなかったとしても、概念的には1930年と同じくらい古いことです。

この物語は、家族の友人がモラビアの国(現在のチェコ共和国の一部)の都市を最小限のコストの電線で接続する方法を理解するためのアルゴリズムを必要としたOtakarBorůvkaから始まります。彼のアルゴリズムは、1926年に数学関連のジャーナルに発表されました。当時、コンピューターサイエンスは存在しなかったためです。これは、ボリフカのアルゴリズムの改善を考えて1930年に公開したヴォイチェフジャーニークに注目されました。彼は、実際には、1957年に再発見したPrimのアルゴリズムと同じアルゴリズムを発見しました。

これらすべてとは独立して、1956年にダイクストラは彼の研究所が開発した新しいコンピューターの機能を実証するプログラムを書く必要がありました。彼はコンピューターでオランダの2つの都市間を移動するための接続を見つけることができればすばらしいと彼は思った。彼はアルゴリズムを20分で設計しました。彼は64の都市のグラフを作成しました(彼のコンピューターは6ビットであったため)単純化し、この1956年のコンピューターのコードを書きました。しかし、主にコンピューターサイエンスジャーナルが存在しないため、彼はアルゴリズムを公開しませんでした。これはあまり重要ではないと考えました。翌年、彼は新しいコンピューターの端子を接続して、ワイヤーの長さを最小限に抑える問題について学びました。彼はこの問題について考え、Jarník/ Prim 'を再発見しました 1年前に彼が発見した最短経路アルゴリズムと同じ手法を再び使用するアルゴリズム。彼彼のアルゴリズムは両方ともペンや紙を使わずに設計されたと述べた。1959年に、彼は両方のアルゴリズムを2ページ半の長さの論文で発表しました。


ありがとう!出口は曖昧ですが、何も起こらなくてもループから出るのはなぜですか?
amirouche

15

ダイクストラは、開始ノードと他のすべてのノードとの間の最短経路を見つけます。したがって、見返りとして、最初のノードから最小距離ツリーを取得します。つまり、他のすべてのノードにできるだけ効率的に到達できます。

Primsアルゴリズムは、特定のグラフのMST、つまりすべてのノードを接続するツリーを取得しますが、すべてのコストの合計は最小です。

現実的な例でストーリーを短くするには:

  1. ダイクストラは、移動時間と燃料を節約して、各目的地までの最短経路を知りたいと考えています。
  2. プリムは、鉄道レールシステムを効率的に展開する方法、つまり材料費を節約する方法を知りたいと考えています。

10

ダイクストラのアルゴリズムのウィキペディアの記事から直接:

ダイクストラのアルゴリズムの基礎となるプロセスは、プリムのアルゴリズムで使用される貪欲なプロセスに似ています。プリムの目的は、グラフ内のすべてのノードを接続する最小のスパニングツリーを見つけることです。ダイクストラは2つのノードのみに関係しています。プリムは、開始ノードからのパスの合計重みを評価せず、個々のパスのみを評価します。


5
「ダイクストラは2つのノードのみに関係しています」は二段です。
tmyklebu 2014

5

最近同じ質問に悩まされて、私の理解を共有したいと思います...

これら2つのアルゴリズム(ダイクストラとプリム)の根本的な違いは、それらが解決するように設計された問題、つまり2つのノード間の最短パスと最小スパニングツリー(MST)の根本だと思います。形式は、たとえばノードst 間の最短経路を見つけることであり、合理的な要件は、グラフの各エッジに最大で1回アクセスすることです。ただし、すべてのノードにアクセスする必要はありません。後者(MST)は、すべてのノードに(最大で1回)アクセスするようにするものであり、各エッジに最大で1回アクセスするという同じ合理的な要件があります。

ことではダイクストラは長い間、私はから得ることができる「テイクショートカット」に私たちを可能にする、と述べたトンの結果を気にせず、 -私が得ればトン、私が行っています!MSTにはsからtへのパスもありますが、このs - tパスは残りのすべてのノードを考慮して作成されるため、このパスは、ダイストラのアルゴリズムで検出されるs - tパスより長くなる可能性があります。以下は、3つのノードを持つ簡単な例です。

                                  2       2  
                          (s) o ----- o ----- o (t)     
                              |               |
                              -----------------
                                      3

上端のそれぞれのコストが2で、下端のコストが3であるとしましょう。中間ノードは関係ないので、ダイクトラは下のパスを取るように指示します。一方、Primは、上部の2つのエッジを持つMSTを返し、下部のエッジを破棄します。

このような違いは、実装の微妙な違いにも反映されています。ダイクストラのアルゴリズムでは、新しいノードを吸収した後、sから最短パスを更新するために(ノードごとに)ブックキーピングステップが必要ですが、Primのアルゴリズムではそのような必要はありません。


3

基本的なアルゴリズムの主な違いは、異なるエッジ選択基準にあります。一般に、どちらも次のノードを選択するために優先キューを使用しますが、現在の処理ノードの隣接ノードを選択するための異なる基準があります。

def dijkstra(g, s):
    q <- make_priority_queue(VERTEX.distance)
    for each vertex v in g.vertex:
        v.distance <- infinite
        v.predecessor ~> nil
        q.add(v)
    s.distance <- 0
    while not q.is_empty:
        u <- q.extract_min()
        for each adjacent vertex v of u:
            ...

def prim(g, s):
    q <- make_priority_queue(VERTEX.distance)
    for each vertex v in g.vertex:
        v.distance <- infinite
        v.predecessor ~> nil
        q.add(v)
    s.distance <- 0
    while not q.is_empty:
        u <- q.extract_min()
        for each adjacent vertex v of u:
            if v in q and weight(u, v) < v.distance:// <-------selection--------
            ...

vertex.distanceの計算は2番目の異なる点です。


3

ダイクストラのアルゴリズムはノードiとjの間の単一ソースの最短経路問題ですが、プリムのアルゴリズムは最小のスパニングツリー問題です。これらのアルゴリズムは、「貪欲なアルゴリズム」というプログラミング概念を使用しています

これらの概念を確認する場合は、にアクセスしてください。

  1. 貪欲アルゴリズム講義ノート:http : //jeffe.cs.illinois.edu/teaching/algorithms/notes/07-greedy.pdf
  2. 最小全域木:http : //jeffe.cs.illinois.edu/teaching/algorithms/notes/20-mst.pdf
  3. 単一ソースの最短パス:http : //jeffe.cs.illinois.edu/teaching/algorithms/notes/21-sssp.pdf

2

ダイクストラアルゴリズムは、最短経路を見つけるためにのみ使用されます。

では最小全域木(プリムのか、クラスカル法)あなたは、最小エッジ値と最小egdesを取得します。

例:-多数のワイヤーを必要とする巨大なネットワークを作成したくない状況を考えてください。ワイヤーのこれらのカウントは、最小スパニングツリー(プリムまたはクラスカルのアルゴリズム) を使用して実行できます(つまり、最小限のコストで巨大な有線ネットワーク接続を作成するための最小限の数のワイヤーを提供します。

一方、「ダイクストラアルゴリズム」は、ノードを相互に接続しながら2つのノード間の最短パスを取得するために使用されます。


2

最も簡単な説明は、プリムでは開始ノードを指定しないことですが、ダイクストラでは(開始ノードが必要)、指定されたノードから他のすべてのノードへの最短パスを見つける必要があります。


0

@templatetypedefは、MSTと最短パスの違いをカバーしています。アルゴリズムの違いについては別の記事で説明しましたので、入力としてもう1つのパラメーターをとる同じ汎用アルゴリズムを使用して両方を実装できることを示して答えてください:function f(u,v)。PrimとDijkstraのアルゴリズムの違いは、単にどちらf(u,v)を使用するかです。


0

コードレベルでは、もう1つの違いはAPIです。

Primはソース頂点sで初期化しPrim.new(s)ます。つまり、sは任意の頂点にすることができ、sに関係なく、最小スパニングツリー(MST)のエッジである最終結果は同じです。MSTエッジを取得するには、メソッドを呼び出しますedges()

ダイクストラをソース頂点sで初期化Dijkstra.new(s)します。つまり、他のすべての頂点への最短パス/距離を取得します。最終結果は、sから他のすべての頂点への最短パス/距離です。sによって異なります。sから任意の頂点vまで最短パス/距離を取得するには、メソッドdistanceTo(v)とをpathTo(v)それぞれ呼び出します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.