Chapter 19 – Advanced Graph Algorithms
Chapter 19: Advanced Graph Algorithms Welcome to Chapter 19, where we’ll explore some of the more advanced algorithms used in graph theory. These algorithms are crucial for solving complex problems related to networks, paths, and flows. In this chapter, we will cover: Shortest Path Algorithms: Dijkstra’s Algorithm Bellman-Ford Algorithm Maximum Flow Algorithms: Ford-Fulkerson Method Edmonds-Karp Algorithm 19.1 Shortest Path Algorithms In graph theory, finding the shortest path between two nodes is a common problem. Depending on the type of graph (directed, undirected, weighted, unweighted), different algorithms can be used to find the shortest paths efficiently. 19.1.1 Dijkstra’s Algorithm Definition: Dijkstra’s Algorithm finds the shortest path from a source node to all other nodes in a graph with non-negative edge weights. It follows a greedy approach by choosing the shortest path at each step. How Dijkstra’s Algorithm Works: Initialize Distances: Start by assigning an infinite distance to all nodes except the source node, which gets a distance of 0. Priority Queue: Use a priority queue to select the node with the smallest known distance. Relaxation: For each neighboring node, check if a shorter path can be found through the current node. If so, update the distance. Repeat: Continue this process until all nodes have been visited and their shortest paths are known. Dijkstra’s Algorithm Example: Consider the graph below: A –1–> B A –4–> C B –2–> C B –6–> D C –3–> D To find the shortest path from A to all other nodes: Initialization: Set the distance to A as 0, and all others as infinity: Distances: A = 0, B = ∞, C = ∞, D = ∞ Priority Queue: Start with A (0). Relaxation: From A, update B (0 + 1 = 1) and C (0 + 4 = 4). New distances: A = 0, B = 1, C = 4, D = ∞ Next Node: Select B (1), update C (1 + 2 = 3) and D (1 + 6 = 7). New distances: A = 0, B = 1, C = 3, D = 7 Next Node: Select C (3), update D (3 + 3 = 6). Final distances: A = 0, B = 1, C = 3, D = 6 The shortest paths from A are: A to B: 1 A to C: 3 A to D: 6 Dijkstra’s Algorithm Implementation in C++: #include <iostream> #include <vector> #include <queue> #include <limits.h> using namespace std; #define INF INT_MAX // Structure for a graph edge struct Edge { int dest, weight; }; // Dijkstra’s algorithm to find the shortest path void dijkstra(vector<vector<Edge>>& graph, int src) { int V = graph.size(); vector<int> dist(V, INF); dist[src] = 0; priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq; pq.push({0, src}); while (!pq.empty()) { int u = pq.top().second; pq.pop(); for (auto edge : graph[u]) { int v = edge.dest; int weight = edge.weight; if (dist[u] + weight < dist[v]) { dist[v] = dist[u] + weight; pq.push({dist[v], v}); } } } cout << "Vertex\tDistance from Source\n"; for (int i = 0; i < V; ++i) cout << i << "\t\t" << dist[i] << "\n"; } int main() { int V = 5; vector<vector<Edge>> graph(V); graph[0].push_back({1, 10}); graph[0].push_back({4, 5}); graph[1].push_back({2, 1}); graph[2].push_back({3, 4}); graph[4].push_back({1, 3}); graph[4].push_back({2, 9}); dijkstra(graph, 0); return 0; } This code illustrates Dijkstra’s algorithm for a graph with 5 vertices. 19.1.2 Bellman-Ford Algorithm Definition: The Bellman-Ford Algorithm is another method for finding the shortest path from a source node to all other nodes, but unlike Dijkstra’s algorithm, it works with graphs that may contain negative weight edges. How Bellman-Ford Algorithm Works: Initialize Distances: Set the distance of the source node to 0 and all other nodes to infinity. Relax All Edges: For each edge, update the distance to its destination if a shorter path is found through the source. Repeat: Perform the relaxation process V-1 times, where V is the number of vertices. Negative Cycle Detection: In the final pass, check for any further distance reductions. If found, a negative weight cycle exists. Example: Consider the graph: A –1–> B B –2–> C C –(-1)–> A B –3–> D To find the shortest path from A: Initialize distances: A = 0, B = ∞, C = ∞, D = ∞. After the first pass: A to B: 1 B to C: 1 + 2 = 3 B to D: 1 + 3 = 4 After the second pass, no changes occur, confirming the final shortest paths. Bellman-Ford Algorithm Implementation in C++: #include <iostream> #include <vector> using namespace std; struct Edge { int u, v, weight; }; void bellmanFord(int V, int E, vector<Edge>& edges, int src) { vector<int> dist(V, INT_MAX); dist[src] = 0; for (int i = 1; i <= V – 1; i++) { for (int j = 0; j < E; j++) { int u = edges[j].u; int v = edges[j].v; int weight = edges[j].weight; if (dist[u] != INT_MAX && dist[u] + weight < dist[v]) { dist[v] = dist[u] + weight; } } } // Check for negative-weight cycles for (int i = 0; i < E; i++) { int u = edges[i].u; int v = edges[i].v; int weight = edges[i].weight; if (dist[u] != INT_MAX && dist[u] + weight < dist[v]) { cout << "Graph contains a negative-weight cycle\n"; return; } } cout << "Vertex\tDistance from Source\n"; for (int i = 0; i < V; i++) cout << i << "\t\t" << dist[i] << "\n"; } int main() { int V = 5, E = 8; vector<Edge> edges = {{0, 1, -1}, {0, 2, 4}, {1, 2, 3}, {1, 3, 2}, {1, 4, 2}, {3, 2, 5}, {3, 1, 1}, {4, 3, -3}}; bellmanFord(V, E, edges, 0); return 0; } The Bellman-Ford algorithm is more versatile than Dijkstra’s because it can handle negative weights but is less efficient in practice. 19.2 Maximum Flow Algorithms In network flow problems, we aim to send as much flow as possible from a source node to a destination node, subject to capacity limits on the edges. Two classic algorithms for finding the maximum
Chapter 19 – Advanced Graph Algorithms Read More »