Merge pull request #2 from Aakash-Panchal27/patch-1

Patch 1
This commit is contained in:
Aakash Panchal 2019-12-24 11:47:15 +05:30 committed by GitHub
commit b21d836224
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 1282 additions and 0 deletions

View File

@ -0,0 +1,442 @@
<script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML"></script>
## Bellman-Ford Algorithm
Dijkstra's algorithm solves the problem of finding single source shortest paths, but it does not work in the case if there are negative edges or negative cycles in the graph.
How do we solve the SSSP problem when the given graph has negative weighted edges?
We have a new algorithm named "**Bellman-Ford algorithm**" which achieves this goal.
## Quiz Time
You are given a directed graph, how many edges can be there on the path between any two nodes at maximum?
Answer: $|V|-1$
## Brute Force
DFS finds out the correct shortest path whether the edge weights are positive or negative, because it searches all the possible paths from the source to the destination.
**Note:** If there is a negative cycle, then it is not possible to find the shortest distance to affected vertices.
## Bellman-Ford algorithm
Bellman-Ford algorithm works on the principal that the path between any two vertices can contain at most $|V|$ vertices or $|V|-1$ edges.
In Bellman-Ford Algorithm, the main step is the relaxation of the edges.
The algorithm relaxes all the outgoing directed edges $|V| - 1$ times.
### Algorithm
1. Same as Dijkstra's Algorithm, mark all the distances to $\infty$ and assign all the parent vertices to some sentinel value (not used before).
2. Assign source to source distance as $0$ and start the algorithm.
3. Loop over all the directed edges.
4. If the relaxation condition below is satisfied, then relax those edges.
**Relaxation Condition:** For an edge from $A \to B$,
$$\text{Distance}[B] < \text{Distance}[A] + \text{EdgeWeight}[A, B]$$
5. Repeat the step 3, $|V|-1$ times.
This is a kind of bottom-up **Dynamic Programming**. After the $k$-th iteration of the outer loop the shortest paths having at most $k$ edges are found.
### Visualization
After the first iteration of the outer loop there will not be any more relaxations.
### Code
```c++
#include <bits/stdc++.h>
using namespace std;
#define MAX_DIST 100000000
// Function to print the required path
void printpath(vector<int>& parent, int vertex, int source, int destination)
{
if(vertex == source)
{
cout << source << "-->";
return;
}
printpath(parent, parent[vertex], source, destination);
cout << vertex << (vertex==destination ? "\n" : "-->");
}
// Object - Edge
struct edge{
// Edge from -> to
// having some weight
int from, to, weight;
edge(int a, int b, int w)
{
from = a;
to = b;
weight = w;
}
};
int main()
{
int no_vertices=5;
// Array of edges
vector<edge> edges;
// Distance and Parent vertex storing arrays
vector<int> distance(no_vertices+1, MAX_DIST), parent(no_vertices+1,-1);
// Edges
edges.push_back(edge(1,2,1));
edges.push_back(edge(2,3,1));
edges.push_back(edge(1,3,2));
edges.push_back(edge(2,4,-10));
edges.push_back(edge(4,3,4));
edges.push_back(edge(3,5,1));
// For the shake of example
int source = 1, destination = 5;
distance[1] = 0;
// Bellman-Ford Algorithm
for (int i = 0; i < no_vertices - 1; i++)
{
// Loop over all the edges
for(int j = 0; j < edges.size() ; j++)
{
if(distance[edges[j].from] != MAX_DIST) {
// Check for the Relaxation Condition
if(distance[edges[j].to] > distance[edges[j].from] + edges[j].weight )
{
distance[edges[j].to] = distance[edges[j].from] + edges[j].weight;
parent[edges[j].to] = edges[j].from;
}
}
}
}
// Shortest distance from source to destination
cout << distance[5] << endl;
// Shortest path
printpath(parent, 5, 1, 5);
return 0;
}
```
### Time Complexity
- $\mathcal{O}(|V| )$ time is taken by outer loop as it runs $|V|-1$ times.
- $\mathcal{O}(|E|)$ time to loop over all the edges in the inner loop.
So the total time complexity will be: $\mathcal{O}(| V | \cdot | E |)$
If there is a negative cycle in the graph, then certainly we can not find the shortest paths. But how to detect the negative cycles?
We can use Bellman-Ford algorithm to detect negative cycles in the graph. How?
## Detection of Negative Cycle
In the algorithm, we are running the outer loop $|V| - 1$times, as there can be at most $|V| - 1$ relaxations on a path between any two vertices.
Now, if there are any more relaxations possible, then there is a negative cycle in the graph. This is how we detect the negative cycle.
So, we will run the outer loop one more time to detect the negative cycle.
```c++
#include <bits/stdc++.h>
using namespace std;
#define MAX_DIST 100000000
// Function to print the required path
void printpath(vector<int>& parent, int vertex, int source, int destination)
{
if(vertex == source)
{
cout << source << "-->";
return;
}
printpath(parent, parent[vertex], source, destination);
cout << vertex << (vertex==destination ? "\n" : "-->");
}
// Object of Edge
struct edge{
// Edge from -> to
// having some weight
int from, to, weight;
edge(int a, int b, int w)
{
from = a;
to = b;
weight = w;
}
};
// Bellman-Ford Algorithm for Negative Cycle
bool Bellman_Ford_NC(vector<edge> & edges, vector<int> & distance, vector<int> & parent)
{
int no_vertices = 5;
for (int i = 0; i < no_vertices - 1; i++)
{
// Loop over all the edges
for(int j = 0; j < edges.size() ; j++)
{
if(distance[edges[j].from] != MAX_DIST)
{
// Check for the Relaxation Condition
if(distance[edges[j].to] > distance[edges[j].from] + edges[j].weight )
{
distance[edges[j].to] = distance[edges[j].from] + edges[j].weight;
parent[edges[j].to] = edges[j].from;
}
}
}
}
bool is_negative_cycle = false;
// Running the outer loop one more time
for(int j = 0; j < edges.size() ; j++)
{
// Check for the Relaxation Condition
if(distance[edges[j].to] > distance[edges[j].from] + edges[j].weight )
{
// Used when finding vertices in NC
distance[edges[j].to] = distance[edges[j].from] + edges[j].weight;
parent[edges[j].to] = edges[j].from;
// There is a negative cycle
is_negative_cycle = true;
}
}
if(is_negative_cycle)
{
cout << "There is a negative cycle in the graph." << endl;
return false;
}
return true;
}
int main()
{
int no_vertices=5;
// Array of edges
vector<edge> edges;
// Distance and Parent vertex storing arrays
vector<int> distance(no_vertices+1, MAX_DIST), parent(no_vertices+1,-1);
// Edges
edges.push_back(edge(1,2,1));
edges.push_back(edge(2,3,5));
edges.push_back(edge(3,1,2));
edges.push_back(edge(2,4,-10));
edges.push_back(edge(4,3,4));
edges.push_back(edge(3,5,1));
// For the shake of example
int source = 1, destination = 5;
distance[1] = 0;
if(Bellman_Ford(edges, distance, parent))
{
// Shortest distance from source to destination
cout << distance[5] << endl;
// Shortest path
printpath(parent, 5, 1, 5);
}
return 0;
}
```
Is it possible to find the vertices involved in the negative cycle? Yes.
## Finding the Negative Cycle
If there is a unique negative cycle, then we can find out the vertices involved in the cycle using the data of the last relaxation edge and parent vertices.
```c++
#include <bits/stdc++.h>
using namespace std;
#define MAX_DIST 100000000
// Function to print the required path
void printpath(vector<int>& parent, int vertex, int source, int destination)
{
if(vertex == source)
{
cout << source << "-->";
return;
}
printpath(parent, parent[vertex], source, destination);
cout << vertex << (vertex==destination ? "\n" : "-->");
}
// Function to print the required path
void printcycle(vector<int>& parent, int vertex, int source, int destination)
{
if(vertex == source)
{
cout << source << "-->";
return;
}
printcycle(parent, parent[vertex], source, destination);
if(vertex == destination)
cout << vertex << "-->" << source << endl;
else
cout << vertex << "-->";
}
// Object - Edge
struct edge{
// Edge from -> to
// having some weight
int from, to, weight;
edge(int a, int b, int w)
{
from = a;
to = b;
weight = w;
}
};
// Bellman-Ford Algorithm
bool Bellman_Ford(vector<edge> & edges, vector<int> & distance, vector<int> & parent)
{
int no_vertices = 5;
for (int i = 0; i < no_vertices - 1; i++)
{
// Loop over all the edges
for(int j = 0; j < edges.size() ; j++)
{
if(distance[edges[j].from] != MAX_DIST)
{
// Check for the Relaxation Condition
if(distance[edges[j].to] > distance[edges[j].from] + edges[j].weight )
{
distance[edges[j].to] = distance[edges[j].from] + edges[j].weight;
parent[edges[j].to] = edges[j].from;
}
}
}
}
bool is_negative_cycle = false;
int last_relaxation = 0;
// Running the outer loop one more time
for(int j = 0; j < edges.size() ; j++)
{
// Check for the Relaxation Condition
if(distance[edges[j].to] > distance[edges[j].from] + edges[j].weight )
{
distance[edges[j].to] = distance[edges[j].from] + edges[j].weight;
parent[edges[j].to] = edges[j].from;
last_relaxation = edges[j].to;
is_negative_cycle = true;
}
}
if(is_negative_cycle)
{
cout << "There is a negative cycle in the graph." << endl;
return last_relaxation;
}
return 0;
}
int main()
{
int no_vertices=5;
// Array of edges
vector<edge> edges;
// Distance and Parent vertex storing arrays
vector<int> distance(no_vertices+1, MAX_DIST), parent(no_vertices+1,-1);
// Edges
edges.push_back(edge(1,2,1));
edges.push_back(edge(2,3,5));
edges.push_back(edge(3,1,2));
edges.push_back(edge(2,4,-10));
edges.push_back(edge(4,3,4));
edges.push_back(edge(3,5,1));
// For the shake of example
int source = 1, destination = 5;
distance[1] = 0;
int last_relaxation = Bellman_Ford(edges, distance, parent);
if(!last_relaxation)
{
// Shortest distance from source to destination
cout << distance[5] << endl;
// Shortest path
printpath(parent, 5, 1, 5);
}
else
{
int trapped = last_relaxation;
// To find the negative_cycle, we can
// use the last relaxation data
// and loop back over parent vertices
// for over no_vertices time, so that
// we get trapped in the negative cycle
for(int i = 0; i < no_vertices; i++)
{
trapped = parent[trapped];
}
// Printing negative_cycle
printcycle(parent, parent[trapped], trapped, parent[trapped]);
}
return 0;
}
```
## Other Shortest Path finding Algorithms
1. All pair shortest path algorithm - **Floyd Warshall Algorithm**.
2. SSSP using Dynamic Programming.
3. Dijkstra's Algorithm

374
Akash Articles/Dijkstra.md Normal file
View File

@ -0,0 +1,374 @@
<script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML"></script>
## Dijkstra's Algorithm
Have you ever used Google Maps?
Ever wondered how it works? How does it tell you the shortest path from point A to B?
At the backside of it, they are using something known as "Shortest Path Finding algorithm". Well, what does the shortest path actually mean?
The **dark** line represents the shortest path from the home to the office, in the diagram below
![Example for shortest path](https://lh3.googleusercontent.com/GaOV_vdJ-V1G3t27g7bHQzeSbBwdl38bjsTp5xdxgFvrfTU5PAB92FDY7y7zzuPA1rT86N9eaQV6)
Do you know how to represent the roads between different places? This is **Weighted Directed Graph** - a directed graph with edges having weights.
## Quiz Time:
Now can you find the shortest path from the source vertex to the target vertex in the image below?
![Quiz](https://lh3.googleusercontent.com/M4ye9O11B0X1C6qp-Ox-m87G0TJpIn_qOmzi8lEwnV_AYPYoDLK3lG528zElEgEVIMADutFRvbEl "Quiz")
Answer: The dark line shows the answer.
![Answer to the quiz problem](https://lh3.googleusercontent.com/nopAw8ZspVs0cI4YPuu4duBbdRRgoaju3mSSCNb_tVuc9jPSyHsflWQOKhpbLt164llxGQ0rZVEh "Answer to the quiz problem")
-- --
Single Source Shortest Path problem (SSSP)
-----------------------------
**Statement**: Given a graph find out the shortest path from a given point to all other points.
### How to solve this problem?
When we talk about the graph we have two standard techniques to traverse: DFS and BFS.
Can you solve this problem using these standard algorithms?
Certainly. We will see how to find the shortest path from the source to the destination using DFS.
Let's look at how can we solve it using DFS.
### Solution using DFS:
**Algorithm:** DFS approach is very simple.
- Start from the source vertex
- Explore all the vertices adjacent to the source vertex
- For each adjacent vertex, If it satisfies the relaxation condition then update the new distance and parent vertex
- Then recurse on it, by considering itself as the new source.
**Relaxation** means if you reach the vertex with less distance than encountered before, then update the data. **Parent vertex** means the vertex by which the particular vertex is reached.
This way DFS will explore all the possible paths from the source vertex to the destination vertex and will find out the shortest path.
Here in the code, we will represent the graph using adjacency list representation:
```c++
#include <bits/stdc++.h>
using namespace std;
#define MAX_DIST 100000000
// Function to print the required path
void printpath(vector<int>& parent, int vertex, int source, int destination)
{
if(vertex == source)
{
cout << source << "-->";
return;
}
printpath(parent, parent[vertex], source, destination);
cout << vertex << (vertex==destination ? "\n" : "-->");
}
void DFS(int source, int destination, vector<vector<pair<int,int> > > &graph, vector<int> &distances, vector<int> &parent)
{
// When we reach at the destination just return
if(source == destination)
return;
// Do DFS over all the vertices connected
// with the source vertex
for(auto vertex: graph[source])
{
// Relaxation of edge:
// If the distance is less than what we
// have encountered uptil now then update
// Distance and Parent vertex
if(distances[vertex.second] > distances[source] + vertex.first)
{
distances[vertex.second] = distances[source] + vertex.first;
parent[vertex.second] = source;
}
// Do DFS over all the vertices connected
// with the source vertex
DFS(vertex.second, destination, graph, distances, parent);
}
}
int main()
{
// Number of vertices in graph
int n = 6;
// Adjacency list representation of the
// Directed Graph
vector<vector<pair<int, int> > > graph;
graph.assign(n + 1, vector<pair<int, int> >());
// Now make the Directed Graph
// Note that edges are
// in the form (weight, vertex ID)
graph[1].push_back( make_pair(1, 2) );
graph[1].push_back( make_pair(6, 2) );
graph[2].push_back( make_pair(1, 4) );
graph[4].push_back( make_pair(1, 3) );
graph[3].push_back( make_pair(1, 5) );
graph[2].push_back( make_pair(7, 5) );
graph[4].push_back( make_pair(3, 6) );
// Array to store the distances
vector<int> distances(n+1, MAX_DIST);
// Array to store the parent vertices
vector<int> parent(n+1, -1);
int source = 1, destination = 5;
distances[source] = 0;
// Do DFS
DFS(source, destination, graph, distances, parent);
int shortest_distance = distances[destination];
// To print shortest_distance
cout << shortest_distance << endl;
// To print the path of the shortest_distance
printpath(parent, destination, source, destination);
return 0;
}
```
### Time Complexity of DFS
As DFS explores all possible paths from the given source vertex to the destination vertex, this may lead to exponential time complexity in a very dense graph.
So, our DFS approach is not efficient. What next?
We have a very interesting and elegant algorithm to solve the problem named " **Dijkstra's Algorithm**". This is the algorithm whose variants are used by most of the path finding applications.
## Dijkstra's Algorithm:
Dijkstra's Algorithm solves SSSP.
Dijkstra's Algorithm is an iterative algorithm similar to **BFS**, but here we have a little twist.
**Algorithm:**
1. Mark the distance between the source and all other vertices to $\infty$ and assign all the parent vertices to some sentinel (not used value).
2. The set is a collection of vertices which is empty at the start of the algorithm.
3. Set the distance between source to source as 0 and add the source vertex to the set.
4. Find the minimum distance vertex from the set and erase it from the set. Mark it as processed. let this vertex be $A$.
5. Explore all the edges connected to $A$.
6. If the edge is connected to the unprocessed vertex and it satisfies the relaxation condition below, then relax that edge and insert the vertex into the set.
**Relaxation Condition:** Let the edge be $A-u$,
$$\text{Distance}[u] < \text{Distance}[A] + \text{EdgeWeight}(A,u)$$
4. If the set is empty, then stop the algorithm.
5. Otherwise, repeat from step 3.
In Dijkstra's Algorithm, we explore the vertices in the way BFS does, however here we have to find the minimum distance vertex from the set.
Which data structure can help us find the minimum distance vertex from the set?
**Priority Queue** is the data structure which achieves this goal in an efficient manner $\mathcal{O}(\log n)$.
**Visualization:**
- Here cloud represents the processed nodes - the nodes whose final shortest distance is found.
- Solid lines represent the edges that are discovered.
- Numbers in square brackets represent the current distance of that vertex from the source vertex.
1. Start from the source vertex 1. ![enter image description here](https://lh3.googleusercontent.com/FjtCUJsZLrgfR91fhg9SnWq6mZ6huoVoP32ps_Z6V1N1saPJNb_BBCIRB_IlilwuPIK87WPul3u7)
2. Vertex 1 discovers vertices 2 and 3. It consequently does the relaxation and adds vertices 2 and 3 in the set.
![enter image description here](https://lh3.googleusercontent.com/2jJ_CHiOTouAQxCrgpeJ6qK25_ZZuFgh-kI1B19Fsl0NoB9m3rtmtupPUJv4ttC2YSg3X-LD5nnq)
3. The minimum distance vertex in the set is vertex 2. So vertex 2 will be the next source vertex.
It will discover vertices 5 and 4.
Now vertex 2 is added to the cloud as it is processed.
![enter image description here](https://lh3.googleusercontent.com/Gjkc7w3DJKA0k9McJPpSk1HOG9nENp15oWoqcQoreTxS1VGCBdgUP2qdzDDE5KFSHc90p6rNDeI6)
4. The next minimum distance vertex is vertex 4.
It relaxes both 3 and 6. Then vertex 4 will be added to the cloud.
![enter image description here](https://lh3.googleusercontent.com/M_6-KvDeY2V3dkJGfwPKwSDqe6crTNIc9S3N-2e6Zel8pTGTnMQEKp4T4O6pSAj3Ss2aNLxYSMkK)
5. Next vertex will be 3. It relaxes 5.
![enter image description here](https://lh3.googleusercontent.com/rQFxj-uiNigNUNA19aiMtd9eqv1hbIzTtv80UFgB3ij7iJchfZnWiFLuxRDM1AQ4uQMHM8ZOWaP7)
6. Now there will not be any more relaxations.
All the vertices in the priority queue will dequeue without adding any new vertex to the set.
![enter image description here](https://lh3.googleusercontent.com/Hnf3MyVP3V6jAck4trl8mWltMwfMRiP7u0NLYgtX99aQ7T5r4MzNFR3_IyHDjQi4K95kI5FC0ZO-)
Now we have found the shortest distances to all the vertices from the given source vertex.
We can use parent array to store parent of the given vertex, and then we can find out the shortest path for any vertex.
```c++
#include <bits/stdc++.h>
using namespace std;
#define MAX_DIST 100000000
// Function to print the required path
void printpath(vector<int>& parent, int vertex, int source, int destination)
{
if(vertex == source)
{
cout << source << "-->";
return;
}
printpath(parent, parent[vertex], source, destination);
cout << vertex << (vertex==destination ? "\n" : "-->");
}
// Dijkstra's Algorithm
int Dijkstra_Algo(vector<vector<pair<int, int> > >& Graph,
int src, int target, vector<int> & distances, vector<int> & parent)
{
// Minimum Priority Queue to keep track of the discovered
// vertex which has the minimum distance
priority_queue<pair<int, int>, vector<pair<int, int> >,
greater<pair<int, int> > > container;
// To check whether vertex is in the cloud
vector<bool> processed(Graph.size());
// Start with source vertex
// Push the source vertex in the
// Priority Queue
container.push(make_pair(0, src));
// Assign distance to source as 0
distances[src] = 0;
while (!container.empty()) {
// Pop the least distance vertex from the Priority Queue
pair<int, int> temp = container.top();
int current_src = temp.second;
// Pop the minimum distance vertex
container.pop();
processed[current_src] = true;
// current source vertex
for (auto vertex : Graph[current_src]) {
// Distance of the vertex from its
// temporary source vertex
int distance = distances[current_src] + vertex.first;
// Relaxation of edge
if (!processed[vertex.second] && distance < distances[vertex.second]) {
// Updating the distance
distances[vertex.second] = distance;
// Updating the parent vertex
parent[vertex.second] = current_src;
// Adding the relaxed edge in the prority queue
container.push(make_pair(distance, vertex.second));
}
}
}
// return the shortest distance
return distances[target];
}
int main()
{
// Number of vertices in graph
int n = 6;
// Adjacency list representation of the
// Directed Graph
vector<vector<pair<int, int> > > graph;
graph.assign(n + 1, vector<pair<int, int> >());
// Now make the Directed Graph
// Note that edges are
// in the form (weight, vertex ID)
graph[1].push_back( make_pair(1, 2) );
graph[1].push_back( make_pair(6, 2) );
graph[2].push_back( make_pair(1, 4) );
graph[4].push_back( make_pair(1, 3) );
graph[3].push_back( make_pair(1, 5) );
graph[2].push_back( make_pair(7, 5) );
graph[4].push_back( make_pair(3, 6) );
// Array to store the distances
vector<int> distances(n+1, MAX_DIST);
// Array to store the parent vertices
vector<int> parent(n+1, -1);
// For example destination is taken as 5
int source = 1, destination = 5;
distances[source] = 0;
// Dijkstra's algorithm
int shortest_distance = Dijkstra_Algo(graph, source, destination, distances, parent);
// To print shortest_distance
cout << shortest_distance << endl;
// To print the path of the shortest_distance
printpath(parent, destination, source, destination);
return 0;
}
```
## Time Complexity of Dijkstra's Algorithm:
1. $\mathcal{O}(|E|)$ time to make the Weighted Directed Graph.
2. $\mathcal{O}(|E| + |V|)$ can be taken by the while loop which is similar to BFS time complexity.
3. $\mathcal{O}(\log |V|)$ time to insert the relaxed vertex in the priority queue.
So the overall complexity of the Dijkstra's Algorithm will be
$$\mathcal{O}((|E| + |V|) \times \log(|V|))$$
Here $|E|$ represents the number of edges in the graph and $|V|$ represents the number of vertices in the graph.
## Limitation of Dijkstra's Algorithm:
When there are negative weight edges in the graph, then Dijkstra's algorithm does not work.
Example:
![Negative Edge Problem in Dijkstra](https://picasaweb.google.com/110514411166133524120/6771365618877108449#6771365621395377650 "negative_edges")
It will find the path from $a$ to $c$ incorrectly.
What if there is a negative cycle in the graph?
**Negative Cycle:** Cycle in which sum of the weights of the edges is negative.
When there is any negative cycle in the graph then Dijkstra's algorithm will run forever, because then we can reach the affected vertices in negative infinite cost.
Note that the graph, we have used, is connected. If you have a vertex which is not connected, then you cannot find the shortest distance to it!
## **Applications of Dijkstra's algorithm:**
1. One very famous variant is the "Widest Path Finding Algorithm", which is an algorithm to finding a path between two vertices of the graph **maximizing the weight of the minimum-weight edge in the path**.
In the practical application, this problem can be seen as a graph with routers as its vertices and edges representing bandwidth between two vertices. Now if we want to find the maximum bandwidth path between two places in the internet connection, then this algorithm is useful which is highly based on Dijkstra's Algorithm.
2. A widely used application of the shortest path algorithm is in network routing protocols "Routing protocol".
## Other Shortest Path Finding Algorithms:
1 Bellman-Ford Algorithm
2. Using Dynamic Programming
3. All Pair Shortest Path Algorithm - **Floyd-Warshall Algorithm**, which finds the shortest path between every pair of vertices.

View File

@ -0,0 +1,291 @@
## All Pair Shortest Path Problem
Statement: Given a graph, Find out the shortest distance paths between every pair of vertices.
## Brute Force
We have seen Dijkstra's algorithm and Bellman-Ford algorithm, which solves the SSSP problem.
We can run these algorithms for every vertex one by one, which solves the given problem.
This will give the complexity of $\mathcal{O}( (|V| + |E|) \cdot |V| \cdot log|V|)$ in the case of Dijkstra's algorithm and $\mathcal{O} (|V|^2 \cdot |E|)$ in the case of Bellman-Ford Algorithm.
**Floyd-Warshall Algorithm** solves all pair shortest path problem in an efficient manner.
## Floyd-Warshall Algorithm
This algorithm is an example of Dynamic Programming. We split the process of finding the shortest paths in several phases.
-- --
### Quiz Time
You are given that the shortest path between two vertices $A$ and $B$ passes through $C$, i.e. $C$ is the intermediate vertex in the shortest path from $A$ to $B$. What can you conclude from it?
Answer: $SD(A, B) = SD(A,C) + SD(C,B)$
$SD$ stands for Shortest Distance.
-- --
The above answer can be proved using contradiction.
The Floyd-Warshall algorithm works based on the above answer.
Before the $i^{th}$ phase of the algorithm, it finds out the shortest distance path between every pair of vertices which uses intermediate vertices only from the set $\{1,2,..,i-1\}$. In every phase of the algorithm, we add one more vertex in the set.
In the $i^{th}$ phase, we update the $distance$ matrix considering the two cases below:
For an entry $distance[a][b]$,
1. If the shortest path between $a$ and $b$ which uses intermediate vertices from the set $\{1,2,...i-1\}$ is longer than the one that uses $\{1,2,...,i\}$, then update the shortest distance path as below:
$distance[a][b] = distance[a][i]+distance[i][b]$
Where $distance[a][b]$ is the shortest distance between $a$ and $b$ which uses intermediate vertices from the set $\{1,2,..,i-1\}$.
2. Otherwise, $distance[a][b]$ will remain unchanged.
### Algorithm
1. Initialize $N \times N$ distance matrix with infinity.
2. Assign every element representing distance between vertex to itself to zero - assign every diagonal element of distance matrix to zero.
3. For all pair of vertices, If there is an edge between $A$ and $B$, then update $distance[A][B]$ to $Edge Weight(A,B)$.
4. Start from the first vertex, say phase $i=1$.
5. For all pairs of the vertices, update the new shortest distance between them using the condition below,
$distance[a][b] > distance[a][i]+distance[i][b]$
6. If $i$ is equal to the number of vertices, then stop otherwise increment $i$ and repeat step $5$.
```c++
#include <bits/stdc++.h>
using namespace std;
#define MAX_DIST 100000000
void Floyd_Warshall(int no_vertices, vector<vector<int> > & distances)
{
// i shows the phase
for(int i = 1; i <= no_vertices; i++)
{
// Update distance matrix for all pairs
for(int a = 1; a <= no_vertices; a++)
{
for(int b = 1; b <= no_vertices; b++)
{
if(distances[a][i] < MAX_DIST && distances[i][b] < MAX_DIST)
distances[a][b] = min(distances[a][b], distances[a][i]+distances[i][b]);
}
}
}
}
int main()
{
int no_vertices=5;
// N*N array to store the distances between every pair
vector<vector<int> > distances(no_vertices+1, vector<int> (no_vertices+1, MAX_DIST));
// Adding the edges virtually by
// updating distance matrix
distances[1][2]=1;
distances[1][3]=-3;
distances[2][4]=2;
distances[2][5]=1;
distances[3][4]=-1;
distances[3][5]=2;
distances[4][5]=1;
for(int i = 1; i <= no_vertices; i++)
distances[i][i] = 0;
Floyd_Warshall(no_vertices, distances);
// Printing the distance matrix
for(int i=1;i<=no_vertices;i++)
{
for(int j=1;j<=no_vertices;j++)
{
if(distances[i][j]!=MAX_DIST)
cout << setw(5) << right << distances[i][j] << " ";
else
cout << setw(5) << right << "INF" << " ";
}
cout << endl;
}
return 0;
}
```
### Time Complexity
As there are three loops, each running number of vertices time, the complexity will be $\mathcal{O}(|V|^3)$.
In worst case, this is better than the brute force approach.
### Path Reconstruction
To reconstruct the path, we have to store the next vertex for each pair and whenever we update the shortest distance we have to update the next vertex as well.
```c++
#include <bits/stdc++.h>
using namespace std;
#define MAX_DIST 100000000
void Floyd_Warshall(int no_vertices, vector<vector<int> > & distances, vector<vector<int> > & next)
{
// i shows the phase
for(int i = 1; i <= no_vertices; i++)
{
// Update distance matrix for all pairs
for(int a = 1; a <= no_vertices; a++)
for(int b = 1; b <= no_vertices; b++)
if( distances[a][b] > distances[a][i]+distances[i][b] &&
distances[a][i] < MAX_DIST && distances[i][b] < MAX_DIST )
{
distances[a][b] = distances[a][i]+distances[i][b];
next[a][b] = next[a][i];
}
}
}
int main()
{
int no_vertices=5;
// N*N array to store the distances between every pair
vector<vector<int> > distances(no_vertices+1, vector<int> (no_vertices+1, MAX_DIST));
// N*N array to store the next vertex for every pair
vector<vector<int> > next(no_vertices+1, vector<int> (no_vertices+1, -1));
// Adding the edges virtually by
// updating distance matrix and
// next vertex matrix
distances[1][2]=1, next[1][2] = 2;
distances[1][3]=-3, next[1][3] = 3;
distances[2][4]=2, next[2][4] = 4;
distances[2][5]=1, next[2][5] = 5;
distances[3][4]=-1, next[3][4] = 4;
distances[3][5]=2, next[3][5] = 5;
distances[4][5]=1, next[4][5] = 5;
// Update all the diagonal elements
for(int i = 1; i <= no_vertices; i++)
{
distances[i][i] = 0;
next[i][i] = i;
}
Floyd_Warshall(no_vertices, distances, next);
// Example of path reconstruction
int source = 1, destination = 5;
while(source != destination)
{
cout << source << " ";
source = next[source][destination];
}
cout << destination << endl;
return 0;
}
```
### Negative Cycle Case
We can use the Floyd-Warshall algorithm to detect the negative cycle and to find the pair of vertices affected by it.
Initially, the distance between the vertex to itself was zero, but if it turns out to be negative at the end of the algorithm, then there is a negative cycle.
```c++
#include <bits/stdc++.h>
using namespace std;
#define MAX_DIST 100000000
void Floyd_Warshall_with_NC(int no_vertices, vector<vector<int> > & distances)
{
// i shows the phase
for(int i = 1; i <= no_vertices; i++)
for(int a = 1; a <= no_vertices; a++)
for(int b = 1; b <= no_vertices; b++)
if( distances[a][b] > distances[a][i]+distances[i][b] &&
distances[a][i] < MAX_DIST && distances[i][b] < MAX_DIST )
distances[a][b] = distances[a][i]+distances[i][b];
bool is_negative_cycle = false;
// Check for negative cycle
for (int i = 1; i <= no_vertices; ++i)
for (int a = 1; a <= no_vertices; ++a)
for (int b = 1; b <= no_vertices; ++b)
{
// If there is a negative cycle, then update the distance to -Infinity
if (distances[a][i] < MAX_DIST && distances[i][i] < 0
&& distances[i][b] < MAX_DIST)
{
distances[a][b] = -MAX_DIST;
is_negative_cycle = true;
}
}
}
if(is_negative_cycle)
{
cout << "The following pairs are affected by the negative cycle:" << endl;
for (int a = 1; a <= no_vertices; ++a)
for (int b = 1; b <= no_vertices; ++b)
if (distances[a][b] = -MAX_DIST)
cout << a << "--" << b << endl;
}
}
int main()
{
int no_vertices=5;
// N*N array to store the distances between every pair
vector<vector<int> > distances(no_vertices+1, vector<int> (no_vertices+1, MAX_DIST));
// Adding the edges virtually by
// updating distance matrix
distances[1][2]=1;
distances[1][3]=-3;
distances[2][4]=2;
distances[4][1]=1;
distances[3][4]=-2;
for(int i = 1; i <= no_vertices; i++)
distances[i][i] = 0;
Floyd_Warshall_with_NC(no_vertices, distances);
return 0;
}
```
### Application of Floyd-Warshall Algorithm
1. "Widest Path Finding Algorithm", which is an algorithm to finding a path between two vertices of the graph **maximizing the weight of the minimum-weight edge in the path**, can be solved using this algorithm.
2. To do optimal routing.
3. In Gauss-Jordan Algorithm, to find reduced form of matrix and inversion matrix.
## Other Shortest Path Finding Algorithms:
1. Using Dynamic Programming
2. Dijkstra's Algorithm
3. Bellman-Ford Algorithm

View File

@ -0,0 +1,175 @@
## Topological Sort of Graph
Topological Sort is the sorting of the vertices in such a way that, for any two vertices $a$ and $b$, if there is a directed edge from $a \to b$ then $a$ must appear before $b$ in the topological ordering.
$a,b,c,d,e$ is the topologically sorted order for the graph below.
![enter image description here](https://lh3.googleusercontent.com/zOBG-tWmznt9QeFbW-SopxIpvyDSH7RgpmYKL9fIgth_TkRQ3sfuxXsDw7iWgmmyGdqip4cay_WS)
## Quiz Time
Is it always possible to find out the topological sort?
No. Whenever there is a cycle in a graph we can not find it.
To find out the topological sort, we will use the standard graph traversal technique DFS with some modification.
## Algorithm
1. Mark all the vertices as unvisited.
2. If there is a unvisited vertex, then run the DFS starting from that vertex. Otherwise stop.
3. Inside DFS, If all the adjacent vertices of the start vertex are visited, then prepend this vertex at the head of the linked list.
4. Go to the step 2.
Starting from the head, the linked list shows the topological sort of the given graph.
**Visualization:**
```c++
#include <bits/stdc++.h>
using namespace std;
#define MAX_DIST 100000000
void dfs(vector<vector<int> > &graph, int start, list<int> &linked_list, vector<bool>& visited)
{
visited[start] = true;
for(auto i: graph[start])
if(!visited[i])
dfs(graph, i, linked_list, visited);
linked_list.push_front(start);
}
void Topological_sort(int no_vertices, vector<vector<int> > &graph)
{
vector<bool> visited(no_vertices + 1);
list<int> linked_list;
for(int i = 1; i <= no_vertices; i++)
if(!visited[i])
dfs(graph, i, linked_list, visited);
for(auto vertex: linked_list)
cout << vertex << " ";
}
int main()
{
int no_vertices = 5;
vector<vector<int> > graph(no_vertices+1, vector<int>());
graph[1].push_back(3);
graph[2].push_back(3);
graph[3].push_back(4);
graph[3].push_back(5);
Topological_sort(no_vertices, graph);
return 0;
}
```
## Quiz Time
Does topological sort give a unique ordering of the vertices?
No, it is not unique in every case, because we can find many orderings which satisfies the condition of topological sort.
In the graph shown in the image above, $b,a,c,d,e$ and $a,b,c,d,e$ both are valid topological sorts.
## Application
1. It is used to find out the shortest distance path efficiently.
2. Scheduling of tasks according to their dependencies on each other, where dependencies are represented by the directed edges.
## Kahn's Algorithm for Topological Sort
We have seen how to find the topological sort using modified DFS. Now, we will see Kahn's algorithm, which is modified BFS.
We will use the indegree of vertices to find the next vertex of the topological ordering. How?
**The main concept**: If the indegree of the vertex is zero, then it must appear before the vertices whose indegrees are greater than zero.
## Algorithm
1. First of all, count the indegrees of all the vertices.
2. Add all the vertices whose indegrees are zero to the queue.
3. Start the loops like BFS.
4. Dequeue a vertex from the queue, say V and append it to the sorting order.
5. Visit all the adjacent vertices of V and decrease the indegrees of all of them by 1.
6. Enqueue all the adjacent vertices whose indegrees become zero.
7. If the queue is empty, then stop the algorithm otherwise continue from the step 4.
**Visualization**
```c++
#include <bits/stdc++.h>
using namespace std;
#define MAX_DIST 100000000
void Topological_sort(int no_vertices, vector<vector<int> > &graph)
{
list<int> topological_order;
vector<int> indegrees(no_vertices + 1);
for(int i = 1; i <= graph.size(); i++)
for(int j = 0; j < graph[j].size(); j++)
indegrees[graph[i][j]]++;
queue<int> que;
for(int i = 1; i <= no_vertices; i++)
if(indegrees[i] == 0)
que.push(i);
while(!que.empty())
{
int V = que.front();
que.pop();
topological_order.push_back(V);
for(auto i: graph[V])
{
--indegrees[i];
if(indegrees[i] == 0)
que.push(i);
}
}
for(auto i: topological_order)
cout << i << " ";
}
int main()
{
int no_vertices = 5;
vector<vector<int> > graph(no_vertices+1, vector<int>());
graph[1].push_back(3);
graph[2].push_back(3);
graph[3].push_back(4);
graph[3].push_back(5);
Topological_sort(no_vertices, graph);
return 0;
}
```
**Variant:** We can use the priority queue in the place of queue if we want smaller indexed vertices to appear first.