@@ -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