Shortest Path Algorithm
Shortest Path Algorithm
1. Dijkstra's algorithm
1.1 Description
Application scope
-
It is available for both directed and non-directed networks with non-negative weights.
-
It can find a cluster of shortest paths from one single source to all other destinations.
-
It can also find a cluster of shortest paths to one destination from to all other sources.
1.2 Procedure of algorithm
Denote:
- \(i=0,1,2,\cdots, n-1\) : node index
- \(i=0\) : the source node
- \(V(i)\) : distance of shortest path \(0 \to i\) (from the source node \(0\) to the node \(i\))
- \(P(i)\) : the predecessor node of node \(i\)
- \([V(i), P(i)]\) : label of node \(i\)
- \([V(i), P(i)]\) : permanent label
- \([V(i), P(i)]^{T}\) : temporary label
- \(S\) : set of nodes with permanent label
- \(T\) : set of nodes with temporary label
Steps:
-
Step 0: Initiation. Label the source node (node \(0\)) with the permanent label:
\[[V(0)=0, P(0)=-] \]- Set
\[i=0, \ S= \{i\}, \ T=\varnothing \] -
Step 1: Check the stopping criterion.
- If every node has the permanent label, then stop. Otherwise, go to Step 2.
-
Step 2: Scan node and update the node label.
- For each node \(j\) without the permanent label that can be reached from node \(i\), do the following two substeps:
-
Step 2.1: If node \(j\) was not labeled before, then compute the temporary labels:
\[[V(j),P(j)]^{T} \quad \text{where } \ V(j)=V(i)+d_{ij}, \ P(j)=i, \ T=T+\{j\} \] -
Step 2.2: If node \(j\) has a temporary label \([V(j),P(j)]^{T}\), and If \(V(j)>V(i)+d_{ij}\), then update
\[V(j)=V(i)+d_{ij}, \ P(j)=i \]- Else, if node \(j\) has a temporary label \([V(j),P(j)]^{T}\), but \(V(j) \leq V(i)+d_{ij}\), don't need to update the label of node \(j\).
-
Step 3: choose the next node.
- Select a node \(r\) in the temporary label set \(T\) with the smallest temporary label \(V(r)\)
\[r = \arg \min_{r \in T} V(r) \quad \text{ and } \quad i = r \]-
Node \(r\) will has the permanent label: \([V(r),P(r)]\).
-
And update sets:
\[S=S+ \{r \}, \ T=T- \{r\} \]- Then, go to Step 1.
1.3 Examples
-
Example 6.3-4 in Ref [1] p.p. 256-257
-
Javascript Demo in Ref [2]
1.4 Algorithm
Denote:
- \(R\) : set of nodes without permanent label
- \(R = N - S\)
- \(\mathbf{D}\) : distance matrix
- \(d_t\) temporary label of node \(i\)
- \(p_t\) temporary label of node \(i\)
The complexity of this algorithm is \(\mathcal{O}(|V|^2+|E|) = \mathcal{O}(|V|^2)\), where \(|V|\) is the number of nodes, and \(|E|\) is the number of edges.
1.5 Implement by Python
Using networkx structure
Using adjacency matrix
Codes: Dijkstra's algorithm by using adjacency matrix
点击查看代码
def ForwardDPforSP(dist_mat, source=0):
'''
dist_mat : 2-d numpy.ndarray, shape of (n, n)
distance matrix
source : start node (index of 'dist_mat')
default '0'
'''
n = dist_mat.shape[0]
# minimal distance from node 0 to i
V = [np.inf for i in range(n)] # V(i)
V[source] = 0.
P = ['' for i in range(n)]
# temporary label set
R = list(range(n))
R.remove(source)
i = source
for k in range(n-1):
d_m = np.inf
for j in R: # V(source) = 0
if V[j] > V[i] + dist_mat[i, j]:
V[j] = V[i] + dist_mat[i, j]
P[j] = i
if d_m > V[j]:
d_m = V[j]
p_t = j
i = p_t
R.remove(i)
return P, V
Using constructed functions in NetworkX
Shortest path related document of NetworkX: website
Get weighted shortest path length and predecessors of each nodes
predecessor, distance = nx.dijkstra_predecessor_and_distance(G, source, weight='weight')
# return: dict
Get a special the shortest weighted path and lengths from specific source to target
path = nx.dijkstra_path(G, source, target, weight='weight')
dist = nx.dijkstra_path_length(G, source, target, weight='weight')
Get a cluster of shortest weighted paths and lengths from a source node.
dist, path = nx.single_source_dijkstra(G, source, target=None, weight='weight'))
path = nx.single_source_dijkstra_path(G, source, target=None, weight='weight')
dist = nx.single_source_dijkstra_path_length(G, source, target=None, weight='weight')
Get shortest weighted paths between all nodes.
path = nx.all_pairs_dijkstra_path(G, source=None, target=None, weight='weight', method='dijkstra')
dist = nx.all_pairs_shortest_path_length(G, source=None, target=None, weight='weight', method='dijkstra')
-
Parameters:
target: to specify the target node- If
target=None, return a dict including all results
- If
-
Return:
path: list or dict of list, a sequence of node label to indicate the path
Test Cases
Codes: test codes
点击查看代码
2. Floyd's algorithm
also called Floyd-Warshall algorithm
2.1 Description
Application scope
- It is available for both directed and non-directed networks.
- It is available for both non-negative and negative weight edge, but with no negative cycles.
- It can find a cluster of shortest paths between any two node.
2.2 Procedure of algorithm
Denote:
- \(\mathbf{D}\) : Distance matrix
- \(\mathbf{S}\) : Sequence matrix, each entry represents a node
- \(s_{ij}=k\) : \(i \to k \to j\) with distance \(d_{ij}\)
- \(s_{ij}=j\) : \(i \to j\) node \(i\) and \(j\) are connected directly.
Steps
-
Step 0 : Define the starting distance matrix \(\mathbf{D}_0\) and node sequence matrix \(\mathbf{S}_0\) (all diagonal elements are blocked). Set \(k = 1\).
-
Let \(\mathbf{D}_0\) be the distance matrix or adjacency matrix
-
Let \(S_{ij} = j\) if \(D_{ij} \leq +\infty\) or \(S_{ij} = \text{None}\)
-
-
Step 1 : For each iteration \(k=1,2,\cdot,n\)
-
Define row \(k\) and column \(k\) as pivot row and pivot column. Apply the triple operation to each element \(d_{ij}\) in \(\mathbf{D}_{k-1}\), for all \(i\) and \(j\).
-
If the condition
\[d_{ik} + d_{jk} \leq d_{ij}, \quad \forall i,j, \text{ and } i \neq k, j \neq k, i \neq j \]is satisfied, update \(\mathbf{D}_{k}\) and \(\mathbf{S}_{k}\):
-
(1) Create \(\mathbf{D}_{k}\) by replacing \(d_{ij}\) in \(\mathbf{D}_{k-1}\) with \(d_{ik} + d_{kj}\)
-
(2) Create \(\mathbf{S}_{k}\) by replacing \(s_{ij}\) in \(\mathbf{S}_{k-1}\) with \(k\)
-
-
Step 2 :Set \(k = k + 1\). If \(k = n + 1\), stop; else go to Step 2.
2.3 Algorithm
The complexity of this algorithm is \(\mathcal{O}(|V|^3)\)
2.4 Implement by Python
2.4.1 Using adjacency matrix
def Floyd(D, S):
n = D.shape[0]
for i in range(n):
for j in range(n):
if j == i: continue
for k in range(n):
if k == i: continue
if D[i,j] > D[i,k] + D[k,j]:
D[i,j] = D[i,k] + D[k,j]
S[i,j] = k
return D, S
2.4.2 Using constructed functions in NetworkX
# Return type of dict
distance = nx.floyd_warshal(G, weight='weight')
# Return type of dict
predecessor, distance = nx.floyd_warshall_predecessor_and_distance(G, weight='weight')
# Return type of nd.array
distance = nx.floyd_warshall_numpy(G, weight='weight')
3. Bellman-Ford's Algorithm
Reference
[1] H. A. Taha, "Section 6.3 Shortest-route Problem" in Operations research: an introduction, Tenth edition, Global edition. Harlow, England London New York Boston Amsterdam Munich: Pearson Education, 2017, p.p. 251-265.
[2] Mathematical Programming, website.
[3] Shortest Paht

浙公网安备 33010602011771号