def match(G, X, Y): # Maximum bipartite matching H = tr(G) # The transposed graph S, T, M = set(X), set(Y), set() # Unmatched left/right + match while S: # Still unmatched on the left? s = S.pop() # Get one Q, P = {s}, {} # Start a traversal from it while Q: # Discovered, unvisited u = Q.pop() # Visit one if u in T: # Finished augmenting path? T.remove(u) # u is now matched break # and our traversal is done forw = (v for v in G[u] if (u, v) not in M) # Possible new edges back = (v for v in H[u] if (v, u) in M) # Cancellations for v in chain(forw, back): # Along out- and in-edges if v in P: continue # Already visited? Ignore P[v] = u # Traversal predecessor Q.add(v) # New node discovered while u != s: # Augment: Backtrack to s u, v = P[u], u # Shift one step if v in G[u]: # Forward edge? M.add((u, v)) # New edge else: # Backward edge? M.remove((v, u)) # Cancellation return M # Matching -- a set of edges
def ford_fulkerson(G, s, t, aug=bfs_aug): # Max flow from s to t H, f = tr(G), defaultdict(int) # Transpose and flow while True: # While we can improve things P, c = aug(G, H, s, t, f) # Aug. path and capacity/slack if c == 0: return f # No augm. path found? Done! u = t # Start augmentation while u != s: # Backtrack to s u, v = P[u], u # Shift one step if v in G[u]: f[u,v] += c # Forward edge? Add slack else: f[v,u] -= c # Backward edge? Cancel slack
def paths(G, s, t): # Edge-disjoint path count H, M, count = tr(G), set(), 0 # Transpose, matching, result while True: # Until the function returns Q, P = {s}, {} # Traversal queue + tree while Q: # Discovered, unvisited u = Q.pop() # Get one if u == t: # Augmenting path! count += 1 # That means one more path break # End the traversal forw = (v for v in G[u] if (u,v) not in M) # Possible new edges back = (v for v in H[u] if (v,u) in M) # Cancellations for v in chain(forw, back): # Along out- and in-edges if v in P: continue # Already visited? Ignore P[v] = u # Traversal predecessor Q.add(v) # New node discovered else: # Didn't reach t? return count # We're done while u != s: # Augment: Backtrack to s u, v = P[u], u # Shift one step if v in G[u]: # Forward edge? M.add((u,v)) # New edge else: # Backward edge? M.remove((v,u)) # Cancellation
def match(G, X, Y): # Maximum bipartite matching H = tr(G) # The transposed graph S, T, M = set(X), set(Y), set() # Unmatched left/right + match while S: # Still unmatched on the left? s = S.pop() # Get one Q, P = {s}, {} # Start a traversal from it while Q: # Discovered, unvisited u = Q.pop() # Visit one if u in T: # Finished augmenting path? T.remove(u) # u is now matched break # and our traversal is done forw = (v for v in G[u] if (u,v) not in M) # Possible new edges back = (v for v in H[u] if (v,u) in M) # Cancellations for v in chain(forw, back): # Along out- and in-edges if v in P: continue # Already visited? Ignore P[v] = u # Traversal predecessor Q.add(v) # New node discovered while u != s: # Augment: Backtrack to s u, v = P[u], u # Shift one step if v in G[u]: # Forward edge? M.add((u,v)) # New edge else: # Backward edge? M.remove((v,u)) # Cancellation return M # Matching -- a set of edges