From 906c985de3b0156ac50a1bd10d0c803f3439cf4e Mon Sep 17 00:00:00 2001 From: Daniel Melo <38673841+danielx285@users.noreply.github.com> Date: Tue, 22 Oct 2019 06:37:43 -0300 Subject: [PATCH] Create dinic.py (#1396) * Create dinic.py Dinic's algorithm for maximum flow * Update dinic.py Changes made. --- graphs/dinic.py | 93 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 graphs/dinic.py diff --git a/graphs/dinic.py b/graphs/dinic.py new file mode 100644 index 000000000..38e91e494 --- /dev/null +++ b/graphs/dinic.py @@ -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)) + +