サーチ…


ダイクストラの最短経路アルゴリズム

続行する前に、Adjacency MatrixとBFSについて簡単に考えておくことをお勧めします

ダイクストラのアルゴリズムは、単一ソース最短経路アルゴリズムとして知られている。これは、道路ネットワークなどのグラフ内のノード間の最短経路を見つけるために使用されます。 1956年にEdsger W. Dijkstraによって考案され、3年後に出版された。

Breadth First Search(BFS)検索アルゴリズムを使用して最短経路を見つけることができます。このアルゴリズムはうまくいきますが、問題は、各パスを通過するコストが同じであることを前提としています。つまり、各エッジのコストは同じです。 Dijkstraのアルゴリズムは、各経路のコストが同じでない最短経路を見つけるのに役立ちます。

まず、Dijkstraのアルゴリズムを書くためにBFSを修正する方法を見てみましょう。次に、それを完全なDijkstraのアルゴリズムにする優先順位キューを追加します。

ソースからの各ノードの距離がd []配列に保持されているとしましょう。同様に、 d [3]は、 d [3]時間がソースからノード3に到達するのにかかる時間を表す。距離がわからない場合は、 無限d [3]に格納します 。また、 コスト[u] [v]uvのコストとする。つまり、 uノードからvノードに行くにはコスト[u] [v]かかります。

コスト[u] [v]説明

エッジリラクゼーションを理解する必要があります。たとえば、あなたの家からは、それがソースであるとしましょう。Aに行くには10分かかります。そして、場所Bに行くのに25分かかります。我々は持っています、

d[A] = 10
d[B] = 25

今度はA地点からB地点に行くのに7分かかるとしましょう。

cost[A][B] = 7

その後、我々は10 + 7 = 17分、代わりに25分かかりますBを配置しようと、場所Aから、 ソースからAを配置するために行くことによって、ソースからBを配置するために行くことができます。そう、

d[A] + cost[A][B] < d[B]

次に、

d[B] = d[A] + cost[A][B]

これはリラクゼーションと呼ばれます。我々は、Vのノード間のuから行きますとD場合は、[U] +コスト[u]が[V] <D [V]、我々は、Dを更新します[V] = D [U] +コスト[U] [V]。

BFSでは、ノードを2回訪問する必要はありませんでした。ノードが訪問されたかどうかだけを確認しました。訪問されなかった場合は、ノードをキューにプッシュして訪問先としてマークし、距離を1ずつ増やします.Dijkstraでは、ノードをキューにプッシュして訪問先で更新する代わりに、新しいエッジを緩和または更新します。一例を見てみましょう:

グラフの例

ノード1ソースであるとしましょう。次に、

d[1] = 0
d[2] = d[3] = d[4] = infinity (or a large value)

まだ距離がわからないので、 d [2]、d [3]d [4]無限に設定するソースの距離はもちろん0です。さて、 ソースから他のノードに移動し、それらを更新できる場合は、それらをキューにプッシュします。例えば、我々は1-2を横切るでしょう。 d [1] + 2 <d [2]としてd [2] = 2とする 。同様に、我々はd [3] = 5とするエッジ1-3を横切る。

5ノード3に行くために交差できる最短距離ではないことが明確に分かります。したがって、BFSのようにノードを1回だけトラバースすることはここでは機能しません。 エッジ2-3を使用してノード2からノード3に行く場合、 d [3] = d [2] + 1 = 3を更新することができる。そのため、1つのノードを何度も更新することができます。あなたは何回尋ねますか?ノードを更新できる最大回数は、ノードのin-degreeの数です。

任意のノードを複数回訪問するための擬似コードを見てみましょう。単にBFSを変更します。

procedure BFSmodified(G, source):
Q = queue()
distance[] = infinity
Q.enqueue(source)
distance[source]=0
while Q is not empty
    u <- Q.pop()
    for all edges from u to v in G.adjacentEdges(v) do
        if distance[u] + cost[u][v] < distance[v]
            distance[v] = distance[u] + cost[u][v]
        end if
    end for
end while
Return distance

これは、ソースからすべてのノードの最短パスを見つけるために使用できます。このコードの複雑さはあまり良くありません。理由は次のとおりです。

BFSでは、 ノード1から他のすべてのノードに移動するとき、 先着順の方法に従います。たとえば、 ノード2を処理する前にソースからノード3に行きました。 ソースからノード3に行くと、 ノード45 + 3 = 8として更新されます 。再びノード3ノード2から更新する場合、ノード43 + 3 = 6として再度更新する必要があります 。したがって、 ノード4は2回更新される。

Dijkstraは、 First come、first serveメソッドの代わりに、最も近いノードを最初に更新すれば、更新が少なくて済みます。前にノード2を処理した場合、 ノード3は前に更新されていて、それに応じてノード4を更新した後、簡単に最短距離を取得します。アイデアは、 ソースに最も近いキューであるノードから選択することです 。ここでPriority Queueを使用すると、キューをポップすると、 ソースから最も近いノードuが取得さます 。どのようにそれを行うのだろうか?これでd [u]の値をチェックします。

擬似コードを見てみましょう:

procedure dijkstra(G, source):
Q = priority_queue()
distance[] = infinity
Q.enqueue(source)
distance[source] = 0
while Q is not empty
    u <- nodes in Q with minimum distance[]
    remove u from the Q
    for all edges from u to v in G.adjacentEdges(v) do
        if distance[u] + cost[u][v] < distance[v]
            distance[v] = distance[u] + cost[u][v]
            Q.enqueue(v)
        end if
    end for
end while
Return distance

擬似コードは、 ソースから他のすべてのノードまでの距離を返します。 1つのノードvの距離を知りたい場合は、 vがキューからポップされたときに値を返すことができます。

負のエッジがある場合、Dijkstraのアルゴリズムは機能しますか?負のサイクルがある場合は、無限ループが発生します。これは毎回コストを削減し続けるためです。負のエッジがあっても、ダイクストラは目標がポップされた直後に復帰しなければ動作しません。しかし、それはDijkstraアルゴリズムではありません。我々は、負のエッジ/サイクルを処理するためにBellman-Fordアルゴリズムを必要とする。

複雑:

BFSの複雑さは、 O(log(V + E))であり、 Vはノードの数であり、 Eはエッジの数である。 Dijkstraの場合、複雑さは似ていますが、 Priority QueueのソートにはO(logV)が必要です。したがって、全体の複雑さは、 O(Vlog(V)+ E)

以下は、Adjacency Matrixを使ったDijkstraの最短経路アルゴリズムを解くJavaの例です

import java.util.*;
import java.lang.*;
import java.io.*;

class ShortestPath
{
    static final int V=9;
    int minDistance(int dist[], Boolean sptSet[])
    {
        int min = Integer.MAX_VALUE, min_index=-1;

        for (int v = 0; v < V; v++)
            if (sptSet[v] == false && dist[v] <= min)
            {
                min = dist[v];
                min_index = v;
            }

        return min_index;
    }

    void printSolution(int dist[], int n)
    {
        System.out.println("Vertex Distance from Source");
        for (int i = 0; i < V; i++)
            System.out.println(i+" \t\t "+dist[i]);
    }

    void dijkstra(int graph[][], int src)
    {

        Boolean sptSet[] = new Boolean[V];

        for (int i = 0; i < V; i++)
        {
            dist[i] = Integer.MAX_VALUE;
            sptSet[i] = false;
        }

        dist[src] = 0;

        for (int count = 0; count < V-1; count++)
        {
            int u = minDistance(dist, sptSet);

            sptSet[u] = true;

            for (int v = 0; v < V; v++)

                if (!sptSet[v] && graph[u][v]!=0 &&
                        dist[u] != Integer.MAX_VALUE &&
                        dist[u]+graph[u][v] < dist[v])
                    dist[v] = dist[u] + graph[u][v];
        }

        printSolution(dist, V);
    }

    public static void main (String[] args)
    {
    int graph[][] = new int[][]{{0, 4, 0, 0, 0, 0, 0, 8, 0},
                                {4, 0, 8, 0, 0, 0, 0, 11, 0},
                                {0, 8, 0, 7, 0, 4, 0, 0, 2},
                                {0, 0, 7, 0, 9, 14, 0, 0, 0},
                                {0, 0, 0, 9, 0, 10, 0, 0, 0},
                                {0, 0, 4, 14, 10, 0, 2, 0, 0},
                                {0, 0, 0, 0, 0, 2, 0, 1, 6},
                                {8, 11, 0, 0, 0, 0, 1, 0, 7},
                                {0, 0, 2, 0, 0, 0, 6, 7, 0}
                                };
        ShortestPath t = new ShortestPath();
        t.dijkstra(graph, 0);
    }
}

プログラムの期待される出力は

Vertex   Distance from Source
0                0
1                4
2                12
3                19
4                21
5                11
6                9
7                8
8                14


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow