web-dev-qa-db-ja.com

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

Dijkstra'sPrim's アルゴリズムの違いを教えてもらえますか?私は、各アルゴリズムが何をするかを知っています。しかし、彼らは私には同じに見えます。ダイクストラのアルゴリズムは最小コストエッジの合計を保存しますが、プリムのアルゴリズムは最大で1つの最小コストエッジを保存します。これは同じではありませんか?

30
Pradit

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

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

したがって、Dijkstra 最小コストで選択したノードから他のノードに移動できますでは、Primでこれを取得できません

48
fersarr

私が見る唯一の違いは、Primのアルゴリズムは最小コストのEdgeを格納するのに対して、Dijkstraのアルゴリズムはソース頂点から現在の頂点までの総コストを格納するということです。

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

簡単な言葉で:

したがって、複数の都市を接続するために列車を展開する場合は、プリムのアルゴリズムを使用します。しかし、ある都市から他の都市にできるだけ時間を節約したい場合は、ダイクストラのアルゴリズムを使用します。

28
Kevindra

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

_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
_

Primの場合はf = w(u, v)を渡し、Dijkstraの場合はf = u.key + w(u, v)を渡します。

もう1つの興味深い点は、上記のGenericでもBreadth First Search(BFS)を実装できることです。ただし、高価な優先キューは実際には必要ないため、やり過ぎになります。上記のGenericアルゴリズムをBFSに切り替えるには、すべての重みを1に強制するのと同じ_f = u.key + 1_を渡します(つまり、BFSはポイントAからBに移動するために必要なエッジの最小数を与えます)。

直観

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

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

歴史的背景

興味深いのは、両方のアルゴリズムの背後にある一般的なバージョンの技術が、電子計算機がなかったときでも概念的には1930年と同じくらい古いことです。

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

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

21
Shital Shah

ダイクストラのアルゴリズムは、ノード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
user1732445

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

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

そうは言っても、ダイクストラは結果を心配することなくsからtに到達できる限り「ショートカット」を取ることができます-tに到達したら、完了です! MSTにはsからtへのパスもありますが、これはs-tパスは残りのすべてのノードを考慮して作成されるため、このパスはsよりも長くなる可能性があります-tDijstraのアルゴリズムによって見つかったパス。以下は、3つのノードを使用した簡単な例です。

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

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

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

1
ccy

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

1
Deepak Yadav