diff --git a/networking_flow/ford_fulkerson.py b/networking_flow/ford_fulkerson.py index b47d3b68f3d1..52c77902c68b 100644 --- a/networking_flow/ford_fulkerson.py +++ b/networking_flow/ford_fulkerson.py @@ -28,30 +28,33 @@ def breadth_first_search(graph: list, source: int, sink: int, parents: list) -> parents: Parent list Returns: - True if there is a node that has not iterated. + True if there is a path from source to sink >>> breadth_first_search(graph, 0, 5, [-1, -1, -1, -1, -1, -1]) True - >>> breadth_first_search(graph, 0, 6, [-1, -1, -1, -1, -1, -1]) - Traceback (most recent call last): - ... - IndexError: list index out of range """ - visited = [False] * len(graph) # Mark all nodes as not visited - queue = [] # breadth-first search queue + num_nodes = len(graph) + visited = [False] * num_nodes + queue = [] # Using list instead of deque - # Source node queue.append(source) visited[source] = True while queue: - u = queue.pop(0) # Pop the front node - # Traverse all adjacent nodes of u - for ind, node in enumerate(graph[u]): - if visited[ind] is False and node > 0: - queue.append(ind) - visited[ind] = True - parents[ind] = u + # Use pop(0) to simulate deque's popleft() + current_node = queue.pop(0) + + # If we reached the sink, we can stop early + if current_node == sink: + return True + + # Check all adjacent nodes + for neighbor, capacity in enumerate(graph[current_node]): + if not visited[neighbor] and capacity > 0: + visited[neighbor] = True + parents[neighbor] = current_node + queue.append(neighbor) + return visited[sink] @@ -80,28 +83,34 @@ def ford_fulkerson(graph: list, source: int, sink: int) -> int: >>> ford_fulkerson(test_graph, 0, 5) 23 """ - # This array is filled by breadth-first search and to store path - parent = [-1] * (len(graph)) + # Create a copy of the graph to avoid modifying the original + residual_graph = [row[:] for row in graph] + num_nodes = len(residual_graph) + parents = [-1] * num_nodes max_flow = 0 - # While there is a path from source to sink - while breadth_first_search(graph, source, sink, parent): - path_flow = int(1e9) # Infinite value - s = sink + # Augment the flow while there is a path from source to sink + while breadth_first_search(residual_graph, source, sink, parents): + # Find the minimum residual capacity along the path + path_flow = float("inf") + current_node = sink - while s != source: - # Find the minimum value in the selected path - path_flow = min(path_flow, graph[parent[s]][s]) - s = parent[s] + # Find the minimum capacity in the path + while current_node != source: + parent_node = parents[current_node] + path_flow = min(path_flow, residual_graph[parent_node][current_node]) + current_node = parent_node + # Add path flow to overall flow max_flow += path_flow - v = sink - while v != source: - u = parent[v] - graph[u][v] -= path_flow - graph[v][u] += path_flow - v = parent[v] + # Update residual capacities of the edges and reverse edges + current_node = sink + while current_node != source: + parent_node = parents[current_node] + residual_graph[parent_node][current_node] -= path_flow + residual_graph[current_node][parent_node] += path_flow + current_node = parent_node return max_flow