diff --git a/Akash Articles/Bellman-Ford.md b/Akash Articles/Bellman-Ford.md new file mode 100644 index 0000000..f0b6a08 --- /dev/null +++ b/Akash Articles/Bellman-Ford.md @@ -0,0 +1,442 @@ + + +## 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 +using namespace std; +#define MAX_DIST 100000000 + +// Function to print the required path +void printpath(vector& 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 edges; + + // Distance and Parent vertex storing arrays + vector 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 +using namespace std; +#define MAX_DIST 100000000 + +// Function to print the required path +void printpath(vector& 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 & edges, vector & distance, vector & 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 edges; + + // Distance and Parent vertex storing arrays + vector 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 +using namespace std; +#define MAX_DIST 100000000 + +// Function to print the required path +void printpath(vector& 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& 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 & edges, vector & distance, vector & 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 edges; + + // Distance and Parent vertex storing arrays + vector 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