The shortest path problem-Dijkstra and Floyd algorithm

Shortest path

The path with the shortest weighted path length between two vertices is the shortest path.

In a weighted graph, the sum of the weights of the edges experienced from one vertex v to another vertex u is called the sum of weighted paths of the path.

Dijkstra

Single source shortest path of weighted graph

step

  1. Initialize the array, and initialize the union S to {0};
  2. Select vj v_j from the vertex set VSvj ,满足 d i s t [ j ] = M i n { d i s t [ i ] , v i ∈ V − S } dist[j] = Min\{dist[i], v_i \in V-S\} dist[j]=Min{ dist[i],viVS} v j v_j vjIs the end point of the shortest path currently found, and another S ∪ {j} S\cup \{j\}S{ j}
  3. Modify this time from v 0 v_0v0Go to any vertex vk v_k on the set VSvk The length of the shortest path: if dist[j] + graph[j] [k] <dist[k], then let dist[k] = dist[j] + graph[j] [k]; path[k] = j
  4. Repeat 2,3 operations n-1 times, until all vertices are included in S

Auxiliary array

  • s[]: mark the vertices that have been calculated. The values ​​in the array are all initialized to 0, and the value of the source point index is initialized to 1.
  • dist[]: Record the current shortest path length from the source point v0 to other vertices. The value in the array is initialized to the weight from the source point to each vertex edge, namely dist[i]=graph[0] [i]
  • path[]: Record the predecessor vertex of the vertex from the shortest path, that is, path[i] is the predecessor vertex of vi on the shortest path from v to vi. Initialization of the values ​​in the array: if there is a directed edge (undirected edge) from the source point v0 to the vertex vi, then path[i] = 0; otherwise, path[i] = -1

Take the following picture as an example:

Insert picture description here

Initialization: Set dist to be the distance from 0 to all nodes; s[0] is set to 1, and the rest is set to 0; path is set to 0 except for 0 and nodes that cannot be reached from 0.
Insert picture description here

The first round: find the smallest value in dist [without comparison if the subscript is set to 1 in s], which is the value corresponding to subscript 2, modify the dist and path arrays according to step 3, and set s[2] to 1
Insert picture description here

Second round: Find the smallest value in dist [without comparison if the subscript is set to 1 in s], which is the value corresponding to subscript 1, modify the dist and path arrays according to step 3, and set s[1] to 1

Insert picture description here

The third round: Find the smallest value in dist [no comparison if the subscript is set to 1 in s], which is the value corresponding to subscript 3, modify the dist and path arrays according to step 3, and set s[3] to 1

Insert picture description here

Fourth round: find the smallest value in dist [without comparison if the subscript is set to 1 in s], which is the value corresponding to subscript 4, modify the dist and path arrays according to step 3, and set s[4] to 1

Insert picture description here

The final result, according to dist, path can get the path and length

Insert picture description here

Code:

C++

void Dijkstra(Graph G, int v){
    
    
    int s[G.vexnum];
    int path[G.vexnum];
    int dist[G.vexnum];
    for(int i=0;i<G.vexnum;i++){
    
    
        dist[i]=G.edge[v][i];
        s[i] = 0;
        if(G.edge[v][i] < MAX)
            path[i]=v;
        else
            path[i]=-1;
    }
    s[v]=1;
    path[v]=-1;
    for(i=0;i<G.vexnum; i++){
    
    
        int min=MAX;
        int u;
        for(int j=0; j<G.vexnum; j++){
    
    
            if(s[j]==0 && dist[j]<min){
    
    
                min=dist[j];
                u=j;
            }
        }
        s[u] = 1;
        for(int j=0; j<G.vexnum; j++){
    
    
            if(s[j]==0 && dist[u] + G.Edges[u][j] < dist[j]){
    
    
                dist[j] = dist[u] + G.Edges[u][j];
                path[j]=u
            }
        }
    }
}

Python

def dijkstra(graph, begin=0):
    dist = []
    s = []
    path = []
    nums = len(graph)
    # 初始化
    for i in range(nums):
        dist.append(graph[begin][i])
        s.append(0)
        if graph[begin][i] < MAX:
            path.append(begin)
        else:
            path.append(-1)
    s[begin] = 1
    path[begin] = -1
    for i in range(nums):
        min_dist = MAX
        min_vex = -1
        for j in range(nums):
            if s[j] == 0 and dist[j] < min_dist:
                min_dist = dist[j]
                min_vex = j
        s[min_vex] = 1
        for k in range(nums):
            if s[k] == 0 and dist[min_vex] + graph[min_vex][k] < dist[k]:
                dist[k] = dist[min_vex] + graph[min_vex][k]
                path[k] = min_vex
    return dist, path

if __name__ == '__main__':
    graph = [
        [0, 5, 3, MAX, 8],
        [MAX, 0, 2, 1, MAX],
        [MAX, MAX, 0, MAX, 4],
        [MAX, MAX, 1, 0, MAX],
        [MAX, MAX, MAX, MAX, MAX]
    ]
    dijkstra(graph)
'''
dist : [0, 5, 3, 6, 7]
path : [-1, 0, 0, 1, 2]
'''

Algorithm complexity O (∣ V ​​∣ 2) O(|V|^2)O ( V 2)

Dijkstra's algorithm is not suitable for graphs with negative weight edges

Floyd

Shortest path between vertices

Algorithm idea

Recursively generate an n-order square matrix sequence A (− 1), A (0),..., A (k),..., A (n − 1) A^{(-1)}, A^ {(0)}, ...,A^{(k)},...,A^{(n-1)}A(1),A(0),...,A(k),...,A(n1)

A ( k ) [ i ] [ j ] A^{(k)}[i][j] A( k ) [i][j]vertexvi v_iviTo vj v_jvj The length of the shortest path, and the number of vertices passed by the path is not greater than k

Recurrence formula

初始化: A ( − 1 ) [ i ] [ j ] = g r a p h [ i ] [ j ] A^{(-1)}[i][j] = graph[i][j] A(1)[i][j]=graph[i][j]

递推方法: A ( k ) [ i ] [ j ] = M i n { A ( k − 1 ) [ i ] [ j ] , A ( k − 1 ) [ i ] [ k ] + A ( k − 1 ) [ k ] [ j ] } , k = 0 , 1 , . . . , n − 1 A^{(k)}[i][j]=Min\{ A^{(k-1)}[i][j], A^{(k-1)}[i][k]+A^{(k-1)}[k][j]\}, k=0,1,...,n-1 A(k)[i][j]=M i n { A(k1)[i][j],A(k1)[i][k]+A(k1)[k][j]},k=0,1,...,n1

Code

C++

void Floyd(Graph G){
    
    
    int A[G.vexnum][G.vexnum];
    for(int i=0; i<G.vexnum;i++)
        for(int j=0; j<G.vexnum;j++)
            A[i][j]=G.Edge[i][j];
    for(int k=0;k<G.vexnum;k++)
        for(int i=0; i<G.vexnum;i++)
            for(int j=0; j<G.vexnum;j++)
                if(A[i][j]>A[i][k]+A[k][j])
                    A[i][j]=A[i][k]+A[k][j];
}

Python

def floyd(graph):
    nums = len(graph)
    A = []
    for i in range(nums):
        a = []
        for j in range(nums):
            a.append(graph[i][j])
        A.append(a)
    print(A)
    for i in range(nums):
        for j in range(nums):
            for k in range(nums):
                if A[i][j] > A[i][k] + A[k][j]:
                    A[i][j] = A[i][k] + A[k][j]
    return A

Take the above picture as an example

if __name__ == '__main__':
    graph = [
        [0, 5, 3, MAX, 8],
        [MAX, 0, 2, 1, MAX],
        [MAX, MAX, 0, MAX, 4],
        [MAX, MAX, 1, 0, MAX],
        [MAX, MAX, MAX, MAX, MAX]
    ]
    # dijkstra(graph)
    A = floyd(graph)
    print(A)
'''
[[0, 5, 3, 6, 7], 
 [100, 0, 2, 1, 6], 
 [100, 100, 0, 100, 4], 
 [100, 100, 1, 0, 5], 
 [100, 100, 100, 100, 100]]
'''

Time complexity O (∣ V ​​∣ 3) O(|V|^3)O ( V 3)

Guess you like

Origin blog.csdn.net/m0_38007695/article/details/110392328