最短経路問題のいくつかのアルゴリズム

フロイドアルゴリズム

使用条件

複数のソースの最短経路を見つけることができ、負の重み側を処理できますが、負のループは発生しません。

時間の複雑さ

O(n 3

説明する

フロイドアルゴリズムは動的計画法を使用しています。

       最初に上の写真を観察します。

       それについて考えてみましょう。これまでの経験によれば、任意の2点間の距離を短くしたい場合(たとえば、頂点aから頂点bまで)、3番目の点(頂点k)のみを導入してこれを渡すことができます。頂点kをa-> k-> bに転送することにより、頂点aから頂点bへの元の距離を短くすることができます。では、この通過の頂点kは1〜nのどれですか?1点だけでなく、2点以上の場合、転送が短くなることもあります。つまり、a-> k1-> k2b->またはa-> k1-> k2 ...-> k-> i ...- > b。たとえば、上の図の都市4から都市3までの距離e [4] [3](4-> 3)は、もともと12でした。都市1のみを通過する場合(4-> 1-> 3)、距離は11に短縮されます(e [4] [1] + e [1] [3] = 5 + 6 = 11)。実際、City 1からCity 3は、City 2を経由して、City 1からCity 3への距離を短くすることもできます(e [1] [2] + e [2] [3] = 2 + 3 = 5 )。したがって、2つの都市を同時に通過する場合、都市4から都市3までの距離はさらに10に短縮されます。この例を通して、各頂点が他の2つの頂点間の距離を短くする可能性があることがわかりました。では、この質問を一般化しましょう。

       3番目のポイントが2つのポイント間を通過できない場合、次のように、これらの都市間の最短距離が初期距離になります。

 

 2点ごとに転送ポイントを設定する場合は、この転送ポイントを使用する前または使用した後に、短いかどうかを確認します。2ポイントと転送ポイントの間の距離は、すでに最短距離です。それは最短の方法でなければなりません。

最も単純で失礼な方法を使用して、開始点、終了点、通過点を列挙するだけで済みます。

状態転送方程式:

d [i] [j] = min(d [i] [k] + d [k] [j]、d [i] [j])

このようにして、フロイドのアルゴリズムのコアコードを簡単に作成できます。

また、「負の重みループ」を含むグラフには最短経路がないため、フロイドアルゴリズムは「負の重みループ」(または「負の重みループ」)を含むグラフを解くことができないことにも注意してください。たとえば、次のグラフには、頂点1から頂点3への最短パスがありません。1-> 2-> 3-> 1-> 2-> 3->…-> 1-> 2-> 3であるため、1->-2> 3などのループが巻かれるたびに、最短パスは最短時間になります1ずつ減少し、最短経路を見つけることはありません。実際、グラフに「負の重みループ」がある場合、このグラフには最短経路はありません。

コアコード

(K = 1 ; K <= N; K ++)// 列挙通過点
    のためには、(私は= 1 ; I <= N; I ++)// 列挙出発点         
        のために(J = 1 ; J <= N; J ++)           // 列挙の終点 
            d [i] [j] = min(d [i] [k] + d [k] [j]、d [i] [j]);

ダイクストラアルゴリズム

使用条件

単一のソースの最短経路を求めることは、負の重みを処理できません。

時間の複雑さ

O(n 2

説明する

ダイクストラアルゴリズムは貪欲法を使用し、d [i]は開始点s0からiまでの最短距離を表します。

開始点s0から開始して、s0に最も近い未訪問のポイントiを選択します。これは最小のd [i]です。エッジの重みが正であるため、iに到達するための短いパスはなくなり、貪欲の正確さが保証されます。 。次に、iを中間点として使用し、iを介して到達できる点の最短距離を更新し、貪欲に進み、訪問されていない最も近い点を見つけます。貪欲のn回の後に、アルゴリズムは終了します。

写真を見てください:

 

この図によると、ダイクストラアルゴリズムはよく理解されているはずです。

コアコード

for(i = 1 ; k <= n; k ++ 
{ 
    maxn = 0x7fffffff ;
     for(j = 1 ; j <= n; j ++)                  // 最小のd [j] 
    {
         if(!vis [j ] && d [j] < maxn)
        { 
            maxn = d [j]; 
            k = i; 
        } 

    } 
    vis [k] = 1 ;
     for(j = 1 ; j <= n; j ++)           // 中間点として、 D [j] 
        if (w [k] [j])kを介して開始点更新し、他の点に到達する
        {
            d [j] =最小{d [k] + w [k] [j]、d [j]}; 
        } 
}

SPFAアルゴリズム

使用条件

単一のソースの最短経路を見つけ、負の重みエッジを処理できます

時間の複雑さ

スパースグラフの場合、O(km)、kはより小さな定数であり、密度の高いグラフまたは構築されたグリッドグラフの場合、O(n * m)に増加します。

説明する

キューを作成します。最初は、キューには開始点のみがあります。開始点からすべての点までの最短パスを記録するテーブルを作成します(テーブルの初期値には最大値を割り当て、この点からそれ自体へのパスには0を割り当てます)。次に、スラック操作を実行し、キュー内のポイントを使用して、開始ポイントからすべてのポイントへの最短パスを更新します。更新が成功し、更新されたポイントがキューにない場合は、ポイントをキューの最後に追加します。キューが空になるまで実行を繰り返します。

図:

 

 

ソースAが最初にチームに入り、ABがリラックスする

ここに画像の説明を挿入

A、B、Cに接続されている側を延長してチームに参加し、リラックスします。

ここに画像の説明を挿入

BとCがそれぞれ拡張を開始し、Dがチームに参加してリラックスする

ここに画像の説明を挿入

Dがチームを離れ、Eがチームに参加してリラックスします。

ここに画像の説明を挿入

Eがキューを離れ、キューが空になり、ソースからすべてのポイントへの最短パスが見つかり、A-> Eの最短パスが8である

ここに画像の説明を挿入

上記はSPFAアルゴリズムのプロセスです。

コアコード

q.push(s); 
vis [s] = 1 ;   // ソースポイントsはエンキューされ、エンキューとしてマークされます
while (q.size())
{ 
       u = q.front(); q.pop(); vis [ u] = 0 ;         // チームのヘッドを削除し、チーム
       参加しないことをマークします(i = head [u]; i; i = next [i])
       { 
              v = ver [i]; 
              w = edge [i];
               if( dis [u] + w < dis [v])
              { 
                     dis [v] = dis [u] + w;
                      if(!vis [v]){q.push(v); vis [v] = 1 ;}     / /キューにない場合は、エンキューし、エンキューをマークします
              }     
       } 
}

 

おすすめ

転載: www.cnblogs.com/arknight/p/12723319.html