1- # Ford-Fulkerson Algorithm for Maximum Flow Problem
21"""
2+ Ford-Fulkerson Algorithm for Maximum Flow Problem
3+ * https://en.wikipedia.org/wiki/Ford%E2%80%93Fulkerson_algorithm
4+
35Description:
4- (1) Start with initial flow as 0;
5- (2) Choose augmenting path from source to sink and add path to flow;
6+ (1) Start with initial flow as 0
7+ (2) Choose the augmenting path from source to sink and add the path to flow
68"""
9+ graph = [
10+ [0 , 16 , 13 , 0 , 0 , 0 ],
11+ [0 , 0 , 10 , 12 , 0 , 0 ],
12+ [0 , 4 , 0 , 0 , 14 , 0 ],
13+ [0 , 0 , 9 , 0 , 0 , 20 ],
14+ [0 , 0 , 0 , 7 , 0 , 4 ],
15+ [0 , 0 , 0 , 0 , 0 , 0 ],
16+ ]
17+
18+
19+ def breadth_first_search (graph : list , source : int , sink : int , parents : list ) -> bool :
20+ """
21+ This function returns True if there is a node that has not iterated.
22+
23+ Args:
24+ graph: Adjacency matrix of graph
25+ source: Source
26+ sink: Sink
27+ parents: Parent list
28+
29+ Returns:
30+ True if there is a node that has not iterated.
731
32+ >>> breadth_first_search(graph, 0, 5, [-1, -1, -1, -1, -1, -1])
33+ True
34+ >>> breadth_first_search(graph, 0, 6, [-1, -1, -1, -1, -1, -1])
35+ Traceback (most recent call last):
36+ ...
37+ IndexError: list index out of range
38+ """
39+ visited = [False ] * len (graph ) # Mark all nodes as not visited
40+ queue = [] # breadth-first search queue
841
9- def bfs (graph , s , t , parent ):
10- # Return True if there is node that has not iterated.
11- visited = [False ] * len (graph )
12- queue = []
13- queue .append (s )
14- visited [s ] = True
42+ # Source node
43+ queue .append (source )
44+ visited [source ] = True
1545
1646 while queue :
17- u = queue .pop (0 )
18- for ind in range (len (graph [u ])):
19- if visited [ind ] is False and graph [u ][ind ] > 0 :
47+ u = queue .pop (0 ) # Pop the front node
48+ # Traverse all adjacent nodes of u
49+ for ind , node in enumerate (graph [u ]):
50+ if visited [ind ] is False and node > 0 :
2051 queue .append (ind )
2152 visited [ind ] = True
22- parent [ind ] = u
53+ parents [ind ] = u
54+ return visited [sink ]
2355
24- return visited [t ]
2556
57+ def ford_fulkerson (graph : list , source : int , sink : int ) -> int :
58+ """
59+ This function returns the maximum flow from source to sink in the given graph.
2660
27- def ford_fulkerson (graph , source , sink ):
28- # This array is filled by BFS and to store path
61+ CAUTION: This function changes the given graph.
62+
63+ Args:
64+ graph: Adjacency matrix of graph
65+ source: Source
66+ sink: Sink
67+
68+ Returns:
69+ Maximum flow
70+
71+ >>> test_graph = [
72+ ... [0, 16, 13, 0, 0, 0],
73+ ... [0, 0, 10, 12, 0, 0],
74+ ... [0, 4, 0, 0, 14, 0],
75+ ... [0, 0, 9, 0, 0, 20],
76+ ... [0, 0, 0, 7, 0, 4],
77+ ... [0, 0, 0, 0, 0, 0],
78+ ... ]
79+ >>> ford_fulkerson(test_graph, 0, 5)
80+ 23
81+ """
82+ # This array is filled by breadth-first search and to store path
2983 parent = [- 1 ] * (len (graph ))
3084 max_flow = 0
31- while bfs (graph , source , sink , parent ):
32- path_flow = float ("Inf" )
85+
86+ # While there is a path from source to sink
87+ while breadth_first_search (graph , source , sink , parent ):
88+ path_flow = int (1e9 ) # Infinite value
3389 s = sink
3490
3591 while s != source :
36- # Find the minimum value in select path
92+ # Find the minimum value in the selected path
3793 path_flow = min (path_flow , graph [parent [s ]][s ])
3894 s = parent [s ]
3995
@@ -45,17 +101,12 @@ def ford_fulkerson(graph, source, sink):
45101 graph [u ][v ] -= path_flow
46102 graph [v ][u ] += path_flow
47103 v = parent [v ]
104+
48105 return max_flow
49106
50107
51- graph = [
52- [0 , 16 , 13 , 0 , 0 , 0 ],
53- [0 , 0 , 10 , 12 , 0 , 0 ],
54- [0 , 4 , 0 , 0 , 14 , 0 ],
55- [0 , 0 , 9 , 0 , 0 , 20 ],
56- [0 , 0 , 0 , 7 , 0 , 4 ],
57- [0 , 0 , 0 , 0 , 0 , 0 ],
58- ]
108+ if __name__ == "__main__" :
109+ from doctest import testmod
59110
60- source , sink = 0 , 5
61- print (ford_fulkerson (graph , source , sink ) )
111+ testmod ()
112+ print (f" { ford_fulkerson (graph , source = 0 , sink = 5 ) = } " )
0 commit comments