def get_random_flow_network(N: int) -> DirectedGraph: """ Losowa sieć przepływu N - liczba warstw sieci źródło - Node #1 ujście - Node #len(graph) """ assert N >= 2 print(f"liczba warstw: {N}") # krok 1: tworzenie warstw node_count_in_layer = [1] + [random.randint(2, N) for _ in range(N)] + [1] node_layer = [None] layer_nodes = [] total = 1 for i, count in enumerate(node_count_in_layer): node_layer.extend([i] * count) layer_nodes.append(list(range(total, total + count))) total += count print(f"liczba wierzchołków w warstwie: {node_count_in_layer}") print(f"wierzchołki w warstwie: {layer_nodes}") # krok 2: losowanie krawędzi między warstwami g = DirectedGraph(size=sum(node_count_in_layer)) for i in range(1, N + 1): for node in layer_nodes[i]: # losowa krawędź wchodząca g.connect(random.choice(layer_nodes[i - 1]), node) # losowa krawędź wychodząca g.connect(node, random.choice(layer_nodes[i + 1])) # krok 3: odajemy 2N losowych łuków edges_added = 0 while edges_added < 2 * N: # brak krawędzi wychodzącej z ujścia n1 = random.randint(1, len(g) - 1) # brak krawędzi wchodzącej do źródła n2 = random.randint(2, len(g)) if n1 == n2 or g.is_connected(n1, n2) or g.is_connected(n2, n1): continue g.connect(n1, n2) edges_added += 1 # krok 4: przypisanie każdej krawędzi losowej przepustowości g.assign_random_weights() return g
def test_connect(self): g = DirectedGraph(8) n1 = 1 n2 = 2 g.connect(n1, n2) assert g.is_connected(n1, n2) assert not g.is_connected(n2, n1) g.disconnect(n1, n2) assert not g.is_connected(n1, n2) g.connect(n1, n2) g.connect(n2, n1) assert g.is_connected(n1, n2) assert g.is_connected(n2, n1)
def ford_fulkerson(g: DirectedGraph, verbose: bool = False) -> Dict[Tuple[int, int], int]: """Edmonds–Karp implementation""" # sieć rezydualna gf = copy.deepcopy(g) # źródło s: Node = 1 # ujście t: Node = len(g) # przepływ krawędzi f = {(e.begin, e.end): 0 for e in g.edges} step = 0 while True: p = get_trail_to_node(breadth_first_search(gf, s, t), t) if p == [t]: if verbose: print("nie istnieje kolejna ścieżka rozszerzająca") break if verbose: print(f"ścieżka rozszerzająca: {p}") p_edges = [gf.edge_to_node(p[i - 1], p[i]) for i in range(1, len(p))] cf_p = min(e.weight for e in p_edges) if verbose: print(f"przepustowość rezydualna ścieżki: {cf_p}") for edge in p_edges: u = edge.begin v = edge.end if g.is_connected(u, v): f[(u, v)] = f[(u, v)] + cf_p else: f[(v, u)] = f[(v, u)] - cf_p if verbose: print(f"kasowanie przepływu, krawędź: ({u}, {v})") # update residual network weights gf.edges = set() for u, v, c in {(e.begin, e.end, e.weight) for e in g.edges}: w1 = c - f[(u, v)] w2 = f[(u, v)] if w1 != 0: gf.connect(u, v, w1) if w2 != 0: gf.connect(v, u, w2) step += 1 return f