|
| 1 | +INF = float("inf") |
| 2 | + |
| 3 | +class Dinic: |
| 4 | + def __init__(self, n): |
| 5 | + self.lvl = [0] * n |
| 6 | + self.ptr = [0] * n |
| 7 | + self.q = [0] * n |
| 8 | + self.adj = [[] for _ in range(n)] |
| 9 | + |
| 10 | + ''' |
| 11 | + Here we will add our edges containing with the following parameters: |
| 12 | + vertex closest to source, vertex closest to sink and flow capacity |
| 13 | + through that edge ... |
| 14 | + ''' |
| 15 | + def add_edge(self, a, b, c, rcap=0): |
| 16 | + self.adj[a].append([b, len(self.adj[b]), c, 0]) |
| 17 | + self.adj[b].append([a, len(self.adj[a]) - 1, rcap, 0]) |
| 18 | + |
| 19 | + #This is a sample depth first search to be used at max_flow |
| 20 | + def depth_first_search(self, vertex, sink, flow): |
| 21 | + if vertex == sink or not flow: |
| 22 | + return flow |
| 23 | + |
| 24 | + for i in range(self.ptr[vertex], len(self.adj[vertex])): |
| 25 | + e = self.adj[vertex][i] |
| 26 | + if self.lvl[e[0]] == self.lvl[vertex] + 1: |
| 27 | + p = self.depth_first_search(e[0], sink, min(flow, e[2] - e[3])) |
| 28 | + if p: |
| 29 | + self.adj[vertex][i][3] += p |
| 30 | + self.adj[e[0]][e[1]][3] -= p |
| 31 | + return p |
| 32 | + self.ptr[vertex] = self.ptr[vertex] + 1 |
| 33 | + return 0 |
| 34 | + |
| 35 | + #Here we calculate the flow that reaches the sink |
| 36 | + def max_flow(self, source, sink): |
| 37 | + flow, self.q[0] = 0, source |
| 38 | + for l in range(31): # l = 30 maybe faster for random data |
| 39 | + while True: |
| 40 | + self.lvl, self.ptr = [0] * len(self.q), [0] * len(self.q) |
| 41 | + qi, qe, self.lvl[source] = 0, 1, 1 |
| 42 | + while qi < qe and not self.lvl[sink]: |
| 43 | + v = self.q[qi] |
| 44 | + qi += 1 |
| 45 | + for e in self.adj[v]: |
| 46 | + if not self.lvl[e[0]] and (e[2] - e[3]) >> (30 - l): |
| 47 | + self.q[qe] = e[0] |
| 48 | + qe += 1 |
| 49 | + self.lvl[e[0]] = self.lvl[v] + 1 |
| 50 | + |
| 51 | + p = self.depth_first_search(source, sink, INF) |
| 52 | + while p: |
| 53 | + flow += p |
| 54 | + p = self.depth_first_search(source, sink, INF) |
| 55 | + |
| 56 | + if not self.lvl[sink]: |
| 57 | + break |
| 58 | + |
| 59 | + return flow |
| 60 | + |
| 61 | +#Example to use |
| 62 | + |
| 63 | +''' |
| 64 | +Will be a bipartite graph, than it has the vertices near the source(4) |
| 65 | +and the vertices near the sink(4) |
| 66 | +''' |
| 67 | +#Here we make a graphs with 10 vertex(source and sink includes) |
| 68 | +graph = Dinic(10) |
| 69 | +source = 0 |
| 70 | +sink = 9 |
| 71 | +''' |
| 72 | +Now we add the vertices next to the font in the font with 1 capacity in this edge |
| 73 | +(source -> source vertices) |
| 74 | +''' |
| 75 | +for vertex in range(1, 5): |
| 76 | + graph.add_edge(source, vertex, 1) |
| 77 | +''' |
| 78 | +We will do the same thing for the vertices near the sink, but from vertex to sink |
| 79 | +(sink vertices -> sink) |
| 80 | +''' |
| 81 | +for vertex in range(5, 9): |
| 82 | + graph.add_edge(vertex, sink, 1) |
| 83 | +''' |
| 84 | +Finally we add the verices near the sink to the vertices near the source. |
| 85 | +(source vertices -> sink vertices) |
| 86 | +''' |
| 87 | +for vertex in range(1, 5): |
| 88 | + graph.add_edge(vertex, vertex+4, 1) |
| 89 | + |
| 90 | +#Now we can know that is the maximum flow(source -> sink) |
| 91 | +print(graph.max_flow(source, sink)) |
| 92 | + |
| 93 | + |
0 commit comments