---
tags: Data structure and algorithm
---
# Graph -- Shortest path algorithm
In the last articles, we talk about the basic concept about graph. Now we are going to talk about the shortest path.
## Relative articles
1. [Graph -- Basic concept](https://hackmd.io/@Justin123/graph1)
2. [Graph -- Shortest path algorithm](https://hackmd.io/@Justin123/graph2) (You're reading now!)
3. [Graph – Spanning Tree](https://hackmd.io/@Justin123/graph3)
## Content
1. [Discussion problems](https://hackmd.io/rbhoKvsgQWmrqyuhMvjmhQ#Discuss-problems)
2. [Intuitive idea for finding the shortest path](https://hackmd.io/rbhoKvsgQWmrqyuhMvjmhQ#Intuitive-idea-for-finding-the-shortest-path)
3. [Algorithm for findind the shortest path](https://hackmd.io/rbhoKvsgQWmrqyuhMvjmhQ#Algorithm-for-findind-the-shortest-path)
4. [Negetive loop](https://hackmd.io/rbhoKvsgQWmrqyuhMvjmhQ#Negetive-loop)
5. [Summary](https://hackmd.io/rbhoKvsgQWmrqyuhMvjmhQ#Summary)
6. [Reference](https://hackmd.io/rbhoKvsgQWmrqyuhMvjmhQ?both#Reference)
## Discuss problems
* **Fastest path**
Justin wanted to buy the latest video games. There were lots of choices for him to reach the department store. How can we find the shortest path for Justin?
---
* **Road Scheduling**
How **Google map** schedule the path for us.
## Intuitive idea for finding the shortest path
Let's say we start from A and we aim to go to E.
```graphviz
graph test {
// title
labelloc="t";
label = "Path\n\n";
rankdir=LR;
A -- B [label = "2"]
B -- C [label = "5"]
A -- C [label = "3"]
C -- D [label = "9"]
B -- D [label = "1"]
B -- E [label = "10"]
D -- E [label = "3"]
}
```
In order to find the $min(A, E)$, we can first find $min(A, B)$ and $min(A, D)$.
```graphviz
graph test {
// title
labelloc="t";
label = "Illustration\n\n";
rankdir=LR;
A -- "..."
"..." -- "D"
"..." -- "B"
}
```
Afterwards, we then compare $min(A, B) \ + weight(B,E)$ and $min(A, D) \ + weight(D, E)$.
```graphviz
graph test {
// title
labelloc="t";
label = "Illustration\n\n";
rankdir=LR;
A -- "..."
"..." -- D
"..." -- B
D -- E [label = "3", color = "red"]
B -- E [label = "10", color = "blue"]
}
```
The smallest one will be the shortest path to E. Using the same way, we can find $min(A, B)$ and $min(A, C)$ to get $min(A, D)$. Below is the pseudocode for shortest path.
```
// Init the distance from A to all the other vertexs
distance[|V|] <- INF_MAX
// Function for finding the shortest path
fun findMinDistance(start, sum)
distance[start] <- sum
for V in adjancent vertex of start
if (distance[V] > sum + weight(start, V))
findMinDistance(V, sum + weight(start, V))
end if
end for
end fun
// Call the function
findMinDistance(A, 0);
```
## Algorithm for findind the shortest path
* **Bellman Ford**
In fact, the algorithm we used here is the same in the intuitive part. However, the difference is that it uses the flag to check whether the path is updated or not and break the loop until there are no updating.
```cpp=
// Edge for DAG
typedef struct edge {
int from, to, cost;
} Edge;
// Edges
Edge edges[number_of_edges];
// Min distance from specific node to others (include itself)
int d[number_of_vertex];
// Function for finding the shortest path from one node to others
void find_shortest(int target) {
// Init the distance to INF
fill(d, d + number_of_vertex, INF_MAX);
// Set the distance to start_node to 0
d[target] = 0
while (true) {
// Flag for checking whether the distance is update or not
bool update = false;
for (int i = 0; i < number_of_edge; ++i) {
Edge next_edge = edges[i];
// Check whether the distance need to update or not
if (d[next_edge.from] != INF_MAX &&
d[next_edge.to] > d[next_edge.from] + next_edge.cost) {
d[next_edge.to] = d[next_edge.from] + next_edge.cost;
update = true;
}
}
// If no update, then break
if (!update) {
break;
}
}
}
```
---
* **Dijkstra**
In fact, we can make progress in **Bellman Ford** algorithm.
1. Update the nodes that are adjacent to the finished node.
2. No repeated uses of the finished node in point 1.
For example, $min(A, B)$ will be decided when we find the weight from A to B. However, in **Bellman Ford** algorithm, we will explore the path from A to B many times.
```graphviz
graph test {
// title
labelloc="t";
label = "Path\n\n";
rankdir=LR;
A -- B [label = "2"]
B -- C [label = "5"]
A -- C [label = "3"]
C -- D [label = "9"]
B -- D [label = "1"]
B -- E [label = "10"]
D -- E [label = "3"]
}
```
In normal event, if we start from A, we can decide the shortest path from A to its adjacent nodes. Afterwards, we can decide other shortest paths as well. However, we have to ensure that ==there are no negative weights in graph.== Otherwise, the weights can be updated again and again.
```cpp=
// Weight for each edge
int cost[number_of_vertex][number_of_vertex];
// Min distance from specific node to others (include itself)
int d[number_of_vertex];
// Check which vertex being used
bool used[number_of_vertex];
void find_shortest(int target) {
// Init the structure
fill(d, d + number_of_vertex, INF);
fill(used, used + number_of_vertex, false);
d[target] = 0;
while (true) {
// vertex to start
int start = -1;
// Find the min distance from the not-used edges
for (int u = 0; u < number_of_vertex; ++u) {
if (!used[u] &&
((start == -1) || d[u] < d[start])) {
start = u;
}
}
// if no update, then break
if (start == -1) {
break;
}
// Set used to true
used[start] = true;
// Update the distance from start to its adjacent vertexs
for (int v = 0; v < number_of_vertex; ++v) {
if (!used[v]) {
d[v] = min(d[u], d[start] + cost[start][v]);
}
}
}
}
```
Here, we have to spend $O(|V|^{2})$ time to find all the nodes and edges. In fact, we can use heap to find the min edges in $O(log|E|)$. Below, we use priority queue to find the shortest path in $O(|V|log|E|)$.
```cpp=
// Edge for DAG
typedef struct edge {
int to, cost;
} Edge;
// First is the min distance, second is the node's number
typedef pair<int, int> P;
// Edges
std::vector<std::vector<Edge> > edges[number_of_nodes];
edges.resize(number_of_edges, 0);
// Min distance from specific node to others (include itself)
int d[number_of_vertex];
void dijkstra(int target) {
// Heap structure for edges
std::priority_queue<P, vector<P>, greater<P> > que;
// Init the structure
std::fill(d, d + number_of_nodes, INF_MAX);
d[target] = 0;
// Push the first node into the queue
que.push(P(0, target));
while (!que.empty()) {
// Pop out min edges
P p = que.top(); que.pop();
int v = p.second;
// If the node already updated, then continue
if (d[v] < p.first) {
continue;
}
// Go through all the edges
for (int i = 0; i < edges[v].size(); ++i) {
Edge e = edges[v][i];
if (d[e.to] > d[v] + e.cost) {
// Update the edge and push it into the queue
d[e.to] = d[v] + e.cost;
que.push(P(d[e.to], e.to));
}
}
}
}
```
---
* **Traces**
In the above session, we only find the number of distances. Now, we want to find how can we reach the shortest path. To achieve this, we only have to use a vector to record the path and update it in the for loop.
```cpp
fill(prev, prev + number_of_vertex, -1);
...
// Go through all the edges
for (int i = 0; i < edges[v].size(); ++i) {
Edge e = edges[v][i];
if (d[e.to] > d[v] + e.cost) {
// Update the edge and push it into the queue
d[e.to] = d[v] + e.cost;
que.push(P(d[e.to], e.to));
prev[e.to] = v;
}
}
...
std::vector<int> get_path(int target) {
std::vector<int> path;
// Go through the path
for (; target != -1; target = prev[target]) {
path.push_back(target);
}
// Reverse the path
std::reverse(path.end(), path.begin());
return path;
}
...
```
## Negetive loop
If the graph has negative loop, we will fail to find the shortest path in finite time.
```graphviz
graph test {
// title
labelloc="t";
label = "Path\n\n";
rankdir=LR;
A -- B [label = "2"]
B -- C [label = "5"]
A -- C [label = "-8"]
}
```
We couldn't find the shortest path in this graph, because **A**, **B** and **C** form a negative loop $(2 + 5 + -8 = -1)$. Therefore, we need a way to detect the negative loop.
To determine the shortest path, we only have to update the distance **(|V| - 1)th** times. Therefore, we can detect that if **|V|th** times is still updating, then there exist at least a negative loop in the graph.
```cpp=
bool find_negative_loop() {
fill(d, d + number_of_vertex, 0);
for (int i = 0; i < number_of_vertex; ++i) {
for (int j = 0; j < number_of_edges; ++j) {
Edge e = edges[j];
if (d[e.to] > d[e.from] + e.cost) {
d[e.to] = d[e.from] + e.cost;
// If times number_of_vertex - 1 still update,
// then there are still negative true
if (i == number_of_vertex - 1) {
return true;
}
}
}
}
return false;
}
```
## Summary
In this article, we talk about how can we find the shortest path. This is different from going through all the vertexs in the graph which we talked about last time. Also, we learned how to find the shortest path with two different algorithm and also learned how to detect negative loop in a graph. Next time, we will talk about the spanning tree.
## Reference
1. [培養與鍛鍊程式設計的邏輯腦 第二版](https://www.books.com.tw/products/0010616945?gclid=Cj0KCQjwoub3BRC6ARIsABGhnyamNtOnA0U1z3yzZeFonqM2HT7jnj1WZcRX8ArR1_KwV3YEgkkkPlIaAlCZEALw_wcB)