Skip to content

Commit 110a4cf

Browse files
committed
Ford Fulkerson Algorithm
1 parent 4d1116d commit 110a4cf

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed

pydatastructs/graphs/algorithms.py

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,3 +1368,134 @@ def dfs(u):
13681368
bridges.append((b, a))
13691369
bridges.sort()
13701370
return bridges
1371+
1372+
def _find_path_dfs(graph, s, t, flow_pass):
1373+
"""
1374+
Finds an augmenting path in a flow network using Depth-First Search (DFS).
1375+
1376+
Parameters
1377+
==========
1378+
graph : Graph
1379+
The flow network graph.
1380+
s : str
1381+
The source node.
1382+
t : str
1383+
The sink node.
1384+
flow_pass : dict
1385+
A dictionary tracking the flow passed through each edge.
1386+
1387+
Returns
1388+
==========
1389+
tuple
1390+
A tuple containing the path flow and a dictionary of parent nodes.
1391+
1392+
Example
1393+
========
1394+
>>> graph = Graph(implementation='adjacency_list')
1395+
>>> graph.add_edge('s', 'o', 3)
1396+
>>> graph.add_edge('s', 'p', 3)
1397+
>>> graph.add_edge('o', 'p', 2)
1398+
>>> graph.add_edge('o', 'q', 3)
1399+
>>> graph.add_edge('p', 'r', 2)
1400+
>>> graph.add_edge('r', 't', 3)
1401+
>>> graph.add_edge('q', 'r', 4)
1402+
>>> graph.add_edge('q', 't', 2)
1403+
>>> flow_passed = {}
1404+
>>> path_flow, parent = _find_path_dfs(graph, 's', 't', flow_passed)
1405+
"""
1406+
1407+
visited = {}
1408+
stack = Stack()
1409+
parent = {}
1410+
1411+
stack.appendd(s)
1412+
visited[s] = True
1413+
1414+
while stack:
1415+
curr = stack.pop()
1416+
1417+
if curr == t:
1418+
break
1419+
1420+
for i in graph.i(curr):
1421+
i_name = i.name
1422+
capacity = graph.get_edge(curr, i_name).value
1423+
flow = flow_pass.get((curr, i_name), 0)
1424+
1425+
if i not in visited and capacity - flow > 0:
1426+
visited[i_name] = True
1427+
parent[i_name] = curr
1428+
stack.append(i_name)
1429+
1430+
if t not in parent and t != s:
1431+
return 0, {}
1432+
1433+
curr = t
1434+
path_flow = float('inf')
1435+
if t == s:
1436+
return 0, {}
1437+
while curr != s:
1438+
prev = parent[curr]
1439+
capacity = graph.get_edge(prev, curr).value
1440+
flow = flow_pass.get((prev, curr), 0)
1441+
path_flow = min(path_flow, capacity - flow)
1442+
curr = prev
1443+
1444+
return path_flow, parent
1445+
1446+
def _max_flow_ford_fulkerson_(graph, s, t):
1447+
"""
1448+
Computes the maximum flow in a flow network using the Ford-Fulkerson algorithm.
1449+
1450+
Parameters
1451+
==========
1452+
graph : Graph
1453+
The flow network graph.
1454+
s : str
1455+
The source node.
1456+
t : str
1457+
The sink node.
1458+
1459+
Returns
1460+
==========
1461+
int
1462+
The maximum flow from the source to the sink.
1463+
1464+
Example
1465+
========
1466+
>>> graph = Graph(implementation='adjacency_list')
1467+
>>> graph.add_edge('s', 'o', 3)
1468+
>>> graph.add_edge('s', 'p', 3)
1469+
>>> graph.add_edge('o', 'p', 2)
1470+
>>> graph.add_edge('o', 'q', 3)
1471+
>>> graph.add_edge('p', 'r', 2)
1472+
>>> graph.add_edge('r', 't', 3)
1473+
>>> graph.add_edge('q', 'r', 4)
1474+
>>> graph.add_edge('q', 't', 2)
1475+
>>> max_flow = _max_flow_ford_fulkerson_(graph, 's', 't')
1476+
"""
1477+
1478+
if s not in graph.vertices or t not in graph.vertices:
1479+
raise ValueError("Source or sink not in graph.")
1480+
1481+
ans = 0
1482+
flow_pass = {}
1483+
1484+
while True:
1485+
path_flow, parent = _find_path_dfs(graph, s, t, flow_pass)
1486+
1487+
if path_flow <= 0:
1488+
break
1489+
1490+
ans += path_flow
1491+
1492+
curr = t
1493+
while curr != s:
1494+
pre = parent[curr]
1495+
fp = flow_pass.get((pre, curr), 0)
1496+
flow_pass[(pre, curr)] = fp + path_flow
1497+
fp = flow_pass.get((curr, pre), 0)
1498+
flow_pass[(curr, pre)] = fp - path_flow
1499+
curr = pre
1500+
1501+
return ans

0 commit comments

Comments
 (0)