Skip to content
71 changes: 40 additions & 31 deletions networking_flow/ford_fulkerson.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]


Expand Down Expand Up @@ -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

Expand Down