def prim2(graph: GraphCore): pq = Heap() visited = set() src = next(iter(graph.vertices)) visited.add(src) edges = set() for edge in graph.get_edges(src).items(): dst, edge_props = edge weight = edge_props['weight'] pq.push((weight, src, dst)) while len(visited) != len(graph.vertices) and pq.size() > 0: top = pq.pop() while pq.size() > 0: weight, src, dst = top if dst not in visited: break top = pq.pop() visited.add(dst) edges.add(top) if len(visited) == len(graph.vertices): break src = dst for edge in graph.get_edges(src).items(): dst, edge_props = edge weight = edge_props['weight'] if dst not in visited: pq.push((weight, src, dst)) return edges
def get_cycle_nodes(graph: GraphCore): ''' 1. Append all the vertices whose degree is 1 to a queue. 2. Pop the queue front and mark it visited. 3. Then decrement neighbours degree by 1. If it becomes 1, add neigh to queue. 4. Repeat 2-3. 5. Whichever nodes are not visited, they are in the cycle. ''' degrees = {} que = deque() for src in graph.vertices: edges = graph.get_edges(src) degrees[src] = len(edges.keys()) if degrees[src] == 1: que.append(src) visited = set() while que: front = que.popleft() assert (front not in visited) visited.add(front) neighbours = graph.get_edges(front).keys() for neigh in neighbours: degrees[neigh] -= 1 if degrees[neigh] == 1: que.append(neigh) return graph.vertices - visited
def compute_longest_path_starting_at(graph: GraphCore, src, longest_distances): if src in longest_distances: return longest_distances[src] longest_path_distance = 1 for neigh, edge_weight in graph.get_edges(src).items(): longest_path_distance = max( longest_path_distance, compute_longest_path_starting_at(graph, neigh, longest_distances) + edge_weight["weight"], ) longest_distances[src] = longest_path_distance return longest_path_distance
def longest_path_dag_topo(graph: GraphCore, src): """ Single-Source Longest Path. Works even for negative edges! First get the topological sort order. Then in that order, do the following for every vertex 'curr': dist[neigh] = max(dist[neigh], dist[curr] + edge_weight). Complexity -> O(V+E) """ topo_order = topo_sort(graph) assert (topo_order is not None) # distances[5] means the longest distance from node 'src' to node 5. distances = {} for vertex in graph.vertices: distances[vertex] = -inf distances[src] = 0 for curr in topo_order: if distances[curr] == -inf: continue for neigh, edge_props in graph.get_edges(curr).items(): weight = edge_props["weight"] distances[neigh] = max(distances[neigh], distances[curr] + weight) return distances
def prim(graph: GraphCore): ''' 1. Let current vertex `u` be vertices[0]. (Any random vertex) 2. Add `u` to the MST vertices set `vertices_in_mst`. 3. Add all the edges (u, v) to a heap for all v not already in MST. 4. Find the lowest edge from heap such that the destination vertex `v` is not already in MST. 5. Let this vertex `v` be the next vertex to process. Goto 1. 6. Loop will end when MST set size === number of vertices. Complexity = O(ElogE) Kruskal is easier to implement and reason about!! ''' edges_in_mst = [] vertices_in_mst = set() # A heap containing the edges connecting MST with non-MST vertices. connecting_edges_pq = PriorityQueue() current_vertex = next(iter(graph.vertices)) vertices_in_mst.add(current_vertex) while len(vertices_in_mst) < len(graph.vertices): vertex_edges = graph.get_edges(current_vertex) for dst, edge_props in vertex_edges.items(): if dst in vertices_in_mst: continue connecting_edges_pq.put((edge_props["weight"], current_vertex, dst)) lightest_edge = connecting_edges_pq.get() dst = lightest_edge[2] while dst in vertices_in_mst: # CAREFUL: Most important step. # Make sure to ignore all the vertices already processed. # Note: We wouldn't have needed this if we could somehow remove # all the edges (*, dst) from the heap efficiently. lightest_edge = connecting_edges_pq.get() dst = lightest_edge[2] edges_in_mst.append(lightest_edge) vertices_in_mst.add(dst) current_vertex = dst return edges_in_mst
def assign_component(src, graph_reverse: GraphCore, parent_mapping, root): if src in parent_mapping: return parent_mapping[src] = root for in_neigh in graph_reverse.get_edges(src): assign_component(in_neigh, graph_reverse, parent_mapping, root)
def visit(src, graph: GraphCore, visited, visit_order): visited.add(src) for neigh in graph.get_edges(src): if neigh not in visited: visit(neigh, graph, visited, visit_order) visit_order.append(src)