forked from TheAlgorithms/Python
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create dinic.py (TheAlgorithms#1396)
* Create dinic.py Dinic's algorithm for maximum flow * Update dinic.py Changes made.
- Loading branch information
1 parent
7444a1f
commit 906c985
Showing
1 changed file
with
93 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
INF = float("inf") | ||
|
||
class Dinic: | ||
def __init__(self, n): | ||
self.lvl = [0] * n | ||
self.ptr = [0] * n | ||
self.q = [0] * n | ||
self.adj = [[] for _ in range(n)] | ||
|
||
''' | ||
Here we will add our edges containing with the following parameters: | ||
vertex closest to source, vertex closest to sink and flow capacity | ||
through that edge ... | ||
''' | ||
def add_edge(self, a, b, c, rcap=0): | ||
self.adj[a].append([b, len(self.adj[b]), c, 0]) | ||
self.adj[b].append([a, len(self.adj[a]) - 1, rcap, 0]) | ||
|
||
#This is a sample depth first search to be used at max_flow | ||
def depth_first_search(self, vertex, sink, flow): | ||
if vertex == sink or not flow: | ||
return flow | ||
|
||
for i in range(self.ptr[vertex], len(self.adj[vertex])): | ||
e = self.adj[vertex][i] | ||
if self.lvl[e[0]] == self.lvl[vertex] + 1: | ||
p = self.depth_first_search(e[0], sink, min(flow, e[2] - e[3])) | ||
if p: | ||
self.adj[vertex][i][3] += p | ||
self.adj[e[0]][e[1]][3] -= p | ||
return p | ||
self.ptr[vertex] = self.ptr[vertex] + 1 | ||
return 0 | ||
|
||
#Here we calculate the flow that reaches the sink | ||
def max_flow(self, source, sink): | ||
flow, self.q[0] = 0, source | ||
for l in range(31): # l = 30 maybe faster for random data | ||
while True: | ||
self.lvl, self.ptr = [0] * len(self.q), [0] * len(self.q) | ||
qi, qe, self.lvl[source] = 0, 1, 1 | ||
while qi < qe and not self.lvl[sink]: | ||
v = self.q[qi] | ||
qi += 1 | ||
for e in self.adj[v]: | ||
if not self.lvl[e[0]] and (e[2] - e[3]) >> (30 - l): | ||
self.q[qe] = e[0] | ||
qe += 1 | ||
self.lvl[e[0]] = self.lvl[v] + 1 | ||
|
||
p = self.depth_first_search(source, sink, INF) | ||
while p: | ||
flow += p | ||
p = self.depth_first_search(source, sink, INF) | ||
|
||
if not self.lvl[sink]: | ||
break | ||
|
||
return flow | ||
|
||
#Example to use | ||
|
||
''' | ||
Will be a bipartite graph, than it has the vertices near the source(4) | ||
and the vertices near the sink(4) | ||
''' | ||
#Here we make a graphs with 10 vertex(source and sink includes) | ||
graph = Dinic(10) | ||
source = 0 | ||
sink = 9 | ||
''' | ||
Now we add the vertices next to the font in the font with 1 capacity in this edge | ||
(source -> source vertices) | ||
''' | ||
for vertex in range(1, 5): | ||
graph.add_edge(source, vertex, 1) | ||
''' | ||
We will do the same thing for the vertices near the sink, but from vertex to sink | ||
(sink vertices -> sink) | ||
''' | ||
for vertex in range(5, 9): | ||
graph.add_edge(vertex, sink, 1) | ||
''' | ||
Finally we add the verices near the sink to the vertices near the source. | ||
(source vertices -> sink vertices) | ||
''' | ||
for vertex in range(1, 5): | ||
graph.add_edge(vertex, vertex+4, 1) | ||
|
||
#Now we can know that is the maximum flow(source -> sink) | ||
print(graph.max_flow(source, sink)) | ||
|
||
|