You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: slides/graphtheory/network_flow_max_flow.txt
+26Lines changed: 26 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -173,6 +173,32 @@ Last is the toString method which was responsible for displaying those nice colu
173
173
174
174
The next class we're going to look at is the NetworkFlowSolverBase class. This class is a generic base for max flow solvers which all solver should extend to gain access to reused variables and setup methods. For example, a simple task like adding an edge to the flow graph should be the same whether the max flow algorithm we're using is Edmond's-Karp, Dinics or some Push-Relabel algorithm; therefore that behavior does not change, so it makes sense to abstract it.
175
175
176
+
Let's take a look at some of the variables I have declared here which all get used by the ford-fulkerson solver.
177
+
178
+
First is, INF short for infinity which is just a handy large constant.
179
+
180
+
Then are the three input variables, n, s and t that track the number of nodes in the graph, the index of the source node and the index of the sink node.
181
+
182
+
Followed by this are two special variables I usually end up using -- because they greatly help boost performance.
183
+
The rational behind using a visited token in combination with an integer array that tracks the visited state of a node is that when we're finding augmenting paths, whether via DFS, BFS or whatever graph traversal method you want to use, you generally want to ensure your augmenting path doesn't don't visit the same node twice, otherwise that could result in a cycle which we don't want.
184
+
The way to check if node 'i' is visited if the state in the visited array at index i is equal to the visited token. This is handy because in the next iteration when we need to again find another augmenting path we also need to mark all nodes as unvisited which we can do simply by incrementing the visitedToken; I know, it's kind of hacky but it's super efficient.
185
+
The alternative is to maintain a boolean visited array and fill it with false before finding any augmenting path. That's not great because it results in an additional order n work every time you want to find an augmenting path.
186
+
187
+
Next is a boolean solved variables which indicates whether the network flow algorithm has ran. The solver only needs to run once because it always yields the same result.
188
+
189
+
Next is the maxFlow value which we're trying to calculate
190
+
191
+
and finally the adjacency list representing the flow graph itself. I highly recommend an adjacency list over an adjacency matrix for network flow problems even though it's a lot more work to setup. I say this mainly because it's common to have sparse flow graphs -- the exception being dense bipartite graphs which are somewhat frequent.
192
+
193
+
Then looking at the constructor, we require the user to specify the number of nodes along with the source and the sink. Then I also take the opportunity to initialize the flow graph and allocate memory for the visited array.
194
+
195
+
In the initializeEmptyFlowGraph method I just initialize each node index to have an empty arraylist of edges so we don't get a null pointer when a user tries to add an edge to the graph.
196
+
197
+
Talking about adding edges to the graph, let's have a look at the addEdge method. Here we need provide the start node and the end node of the directed edge and a positive capacity. In this method we not only create the forward edge but also it's associated residual edge. To do that create another edge in the reverse direction and give it a capacity of zero -- then make the forward edge's residual edge the residual edge and the residual edges residual edge the forward edge -- and finally add them both to the flow graph.
198
+
199
+
The remaining methods are client facing methods -- they can be used to get the residual graph after the solver has been executed and obtain the maximum flow.
200
+
201
+
You'll notice that I ensure that the solve method is only ever called once. The solve method needs to be implemented by the child class -- it's the method that finds augmenting paths through the flow graph and augments the flow.
0 commit comments