def hitBricks(self, grid, hits): """ :type grid: List[List[int]] :type hits: List[List[int]] :rtype: List[int] """ m, n = len(grid), len(grid[0]) # extra dummy node m * n to connect to all nodes in first row uf = UnionFind(m * n + 1) # mark all hits so that they won't be unioned initially for i, j in hits: if grid[i][j] == 1: grid[i][j] = 2 # traversing the grid is slow, can improve it with dfs on hit points for i in range(m): for j in range(n): if grid[i][j] == 1: self.union_around(i, j, grid, uf) # number of nodes connected to dummy node after all hits count = uf.counts[uf.find(m * n)] res = [0] * len(hits) # roll back for i in range(len(hits) - 1, -1, -1): x, y = hits[i] if grid[x][y] == 2: # add the hit back and union bricks around grid[x][y] = 1 self.union_around(x, y, grid, uf) new_count = uf.counts[uf.find(m * n)] res[i] = max(new_count - count - 1, 0) count = new_count return res
def findRedundantDirectedConnection(self, edges): """ :type edges: List[List[int]] :rtype: List[int] """ uf = UnionFind(len(edges) + 1) candidates = self.find_candidates(edges) # no nodes have two parents: fall back to Q1 if not candidates: for p, q in edges: if uf.find(p) == uf.find(q): return [p, q] uf.union(p, q) # remove the last edge that makes the graph a valid tree else: # union all edges except for the second candidate # if a cycle is found during the process # (not necessarily when the two nodes of first candidates are unioned) # the first candidate must be removed for p, q in edges: if p == candidates[1][0] and q == candidates[1][1]: continue if uf.find(p) == uf.find(q): return candidates[0] uf.union(p, q) return candidates[1]
def minMalwareSpread(self, graph, initial): """ :type graph: List[List[int]] :type initial: List[int] :rtype: int """ if not initial: return -1 # return the smallest index if multiple results initial.sort() n = len(graph) uf = UnionFind(n) # union the whole graph for i in range(n): for j in range(i + 1, n): if graph[i][j] == 1: uf.union(i, j) # if only one initially infected node, the damage reduced will be the group size # => return the infected node in the largest group # if 2+ initially infected node in a group, cannot reduce the damage # => return the infected node with minimum index counter = collections.Counter( uf.find(i) for i in initial) # group_parent => # of initially infected nodes one_infected = [i for i in initial if counter[uf.find(i)] == 1] if one_infected: return max(one_infected, key=lambda i: uf.sizes[uf.find(i)]) else: return min(initial)
class ClusterGraph(): def __init__(self): self.edges = [] self.union_find = UnionFind() def add_edge(self, edge): self.edges.append(edge) self.union_find.add_element(edge[0]) self.union_find.add_element(edge[1]) def clusterfy(self, num_clusters=4): self.sort_edges() while len(self.union_find.clusters) > num_clusters: edge = self.edges.pop() leader1 = self.union_find.find(edge[0]) leader2 = self.union_find.find(edge[1]) if leader1 != leader2: self.union_find.union(leader1, leader2) def sort_edges(self): self.edges.sort(key=lambda edge: edge[2], reverse=True) def get_maximum_spacing(self): final_edges = [] for edge in self.edges: leader1 = self.union_find.find(edge[0]) leader2 = self.union_find.find(edge[1]) if leader1 != leader2: final_edges.append(edge) return min(final_edges, key=lambda edge: edge[2])[2]
def numIslands2(self, m, n, positions): """ :type m: int :type n: int :type positions: List[List[int]] :rtype: List[int] """ uf = UnionFind(m * n) added = set() count = 0 # current number of islands res = [] for i, j in positions: p = i * n + j added.add((i, j)) count += 1 for x, y in [(i - 1, j), (i, j - 1), (i + 1, j), (i, j + 1)]: if 0 <= x < m and 0 <= y < n and (x, y) in added: q = x * n + y # reduce count if two nodes are connected # but currently in different trees if uf.find(p) != uf.find(q): count -= 1 uf.union(p, q) res.append(count) return res
def kruskal(size, weights): union_find = UnionFind(size) for u, v in sorted(weights, key=weights.get): if union_find.find(u) != union_find.find(v): union_find.union(u, v) yield u, v
def labeling(char_voxel, bool_voxel): # labeling target is boundary voxels nonzero = np.nonzero(bool_voxel) targets = np.array(nonzero).transpose() normals = get_normals(char_voxel, targets) idx = np.zeros(char_voxel.shape, dtype=np.int32) labels = np.full(char_voxel.shape, -1, dtype=np.int32) target_length = targets.shape[0] uf = UnionFind(target_length) # connection kernel(3x3) p1 = [-1, -1, -1, 0, 0, 0, 1, 1, 1] p2 = [-1, 0, 1, -1, 0, 1, -1, 0, 1] # connection kernel(2x2) q1 = [-1, -1, -1, 0, 0] q2 = [-1, 0, 1, -1, 0] arr = np.arange(target_length) print(idx[nonzero].shape) idx[nonzero] = arr for id, p in enumerate(targets): if id % 10000 == 0: print(id) #idx[p[0], p[1], p[2]] = id for i in range(9): if labels[p[0], p[1] + p1[i], p[2] + p2[i]] == -1: # not in boundary voxel continue idn = idx[p[0], p[1] + p1[i], p[2] + p2[i]] #if 0.1 < np.dot(normals[id,:], normals[idn, :]): # uf.union(idn, id) uf.union(idn, id) #if p[0]<2 or p[1]<2 or p[2] < 2: # labels[p[0], p[1], p[2]] = uf.find(id) # continue for i in range(9): if labels[p[0] - 1, p[1] + p1[i], p[2] + p2[i]] == -1: # not in boundary voxel continue idn = idx[p[0] - 1, p[1] + p1[i], p[2] + p2[i]] #if 0.1 < np.dot(normals[id,:], normals[idn, :]): # uf.union(idn, id) uf.union(idn, id) labels[p[0], p[1], p[2]] = uf.find(id) # labels lookup table lut = np.full(target_length, -1, dtype=np.int32) lbl_max = 0 for i in range(target_length): fi = uf.find(i) if fi == i and uf.count[i] > 10: lut[i] = lbl_max lbl_max += 1 print("label count: {}".format(lbl_max)) for i in range(target_length): fi = uf.find(i) if lut[fi] != -1: labels[targets[i, 0], targets[i, 1], targets[i, 2]] = lut[fi] return labels
def test_union_when_already_united(self): uf = UnionFind([[1,2,3],[4,5],[6,7,8,9,0]]) self.assertEqual(uf.find(1), 1) self.assertEqual(uf.find(2), 1) uf.union(1,2) self.assertEqual(uf.find(1), 1) self.assertEqual(uf.find(2), 1)
def build_mst(n, edges): # edge (w, (u, v)) tree_edges = [] pset = UnionFind(n + 1) edges.sort() for w, e in edges: u, v = e if pset.find(u) != pset.find(v): pset.union(u, v) tree_edges.append((u, v)) return tree_edges
def test_union(self): uf = UnionFind([[1,2,3],[4,5],[6,7,8,9,0]]) self.assertEqual(uf.find(2), 1) self.assertEqual(uf.find(5), 4) uf.union(2,5) self.assertEqual(uf.find(1), 1) self.assertEqual(uf.find(2), 1) self.assertEqual(uf.find(3), 1) self.assertEqual(uf.find(4), 1) self.assertEqual(uf.find(5), 1)
def findRedundantConnection(self, edges): """ :type edges: List[List[int]] :rtype: List[int] """ uf = UnionFind(len(edges) + 1) for p, q in edges: if uf.find(p) == uf.find(q): return [p, q] uf.union(p, q)
def kruskals(g): edges = sorted(g.edges, key=lambda e: e[2]) u = UnionFind() # set up all the cities as trees in UF for city in g.cities: u.makeset(city) mst = [] for e in edges: q, v, _ = e if u.find(q) != u.find(v): mst.append(e) u.union(q, v) return mst
def mst_kruskal(grafo): """Pre: el grafo es no dirigido. Retorna un arbol de tendido minimo.""" conjuntos = UnionFind(grafo.obtener_todos_los_vertices()) #ordenar las aristas de forma ascendente por peso. aristas = sorted(grafo.obtener_todas_las_aristas(), key=itemgetter(2)) arbol = Grafo(False) for v in grafo.obtener_todos_los_vertices(): arbol.agregar_vertice(v, grafo.ver_dato_vertice(v)) for v, w, p in aristas: if conjuntos.find(v) == conjuntos.find(w): continue arbol.agregar_arista(v, w, p) conjuntos.union(v, w) return arbol
def validTree(self, n, edges): """ :type n: int :type edges: List[List[int]] :rtype: bool """ uf = UnionFind(n) # no cycles for p, q in edges: if uf.find(p) == uf.find(q): return False uf.union(p, q) # no forest return uf.num_groups == 1
class MinWTFeedbackEdgeSet: def __init__(self, g): self.edge_set = [] self.g = g self.heap = MaxHeap() self.UF = UnionFind(g.V) self.populateHeap() self.populate_edge_set() def populateHeap(self): edges = set() for i in range(self.g.V): for edge in self.g.adj(i): edges.add(edge) for edge in edges: self.heap.add_item(edge) def populate_edge_set(self): #import pdb; pdb.set_trace() while not self.heap.empty(): edge = self.heap.del_max() if not self.UF.find(edge.either(), edge.other(edge.either())): self.UF.union(edge.either(), edge.other(edge.either())) else: self.edge_set.append(edge) def get_mst(self): return self.edge_set
def clustering(g, num_nodes, k): different_clusters, index = [], 0 g.sort() uf = UnionFind(num_nodes) while uf.size() > k: cost, u, v = g[index] uf.union(u, v) index += 1 for cost, u, v, in g: u_leader, v_leader = uf.find(u), uf.find(v) if u_leader != v_leader: different_clusters.append(cost) return min(different_clusters)
def kruskal(g): MST = [] MST_weight = 0 # initializing Union Find U = UnionFind() U.initialize(g.V) # initializing heap heap = Heap() for e in g.E: heap.push([e[2], (e[0], e[1])]) # [cost, edge] while not (len(MST) == g.n - 1 or heap.is_empty()): aux_edge = heap.pop() edge = [aux_edge[1][0], aux_edge[1][1], aux_edge[0]] # v1, v2, cost e0_find = U.find(edge[0]) e1_find = U.find(edge[1]) if e0_find != e1_find: MST.append(edge) MST_weight += edge[2] # weighting MST U.union(e0_find, e1_find) return MST, MST_weight
class KruskalsMST: def __init__(self, g): self.mst = [] self.g = g self.heap = MinHeap() self.UF = UnionFind(g.V) self.populateHeap() self.populate_mst() def populateHeap(self): edges = set() for i in range(self.g.V): for edge in self.g.adj(i): edges.add(edge) for edge in edges: self.heap.add_item(edge) def populate_mst(self): while len(self.mst) < self.g.V - 1 and not self.heap.is_empty(): edge = self.heap.del_min() if not self.UF.find(edge.either(), edge.other(edge.either())): self.mst.append(edge) self.UF.union(edge.either(), edge.other(edge.either())) def get_mst(self): return self.mst
def kruskal(g): V = g.number_of_nodes() edges = sorted(g.edges(data="weight"), key=lambda x: x[2]) uf = UnionFind(V) mst = [0] * (V-1) e = i = 0 while e < V-1: edge = edges[i] src, des, _ = edge if uf.find(src) != uf.find(des): uf.union(src, des) mst[e] = (src, des) e += 1 i += 1 return mst
def kruskal(graph): ret = 0 result = [] edges = [] for u in graph: for v, c in graph[u]: edges.append((u, v, c)) edges.sort(key=lambda x: x[2]) uf = UnionFind(len(graph.V)) for u, v, c in edges: if uf.find(u) == uf.find(v): continue uf.union(u, v) result.append((u, v)) ret += c return ret, result
def build_disjoint_set(self, num_vertices, edges): ds = UnionFind(num_vertices) for u, v in edges: root_u = ds.find(u) root_v = ds.find(v) if root_u != root_v: ds.join(root_u, root_v) return ds
def test_union_find(self): elements = [1, 2, 3, 4, 6, 7, 8] u1 = UnionFind(elements) for e in elements: self.assertEqual(e, u1.find(e)) new_parent = u1.union(1, 2) self.assertEqual(1, new_parent) new_parent = u1.union(3, 4) self.assertEqual(3, new_parent) new_parent = u1.union(2, 4) self.assertEqual(1, new_parent) self.assertEqual(1, u1.find(4)) new_parent = u1.union(3, 4) self.assertEqual(1, new_parent) new_parent = u1.union(3, 8) self.assertEqual(1, new_parent) new_parent = u1.union(8, 3) self.assertEqual(1, new_parent)
class ClusterNodesOnly(): def __init__(self): self.union_find = UnionFind() self.one_distances = [] self.two_distances = [] def find_all_one_distances(self, node): possible_nodes = [] for bit in range(0, len(node)): search_node = node.copy() bit_to_change = "0" if node[bit] == '1' else "1" search_node[bit] = bit_to_change if tuple(search_node) in self.union_find.node_leaders: possible_nodes.append(search_node) return possible_nodes def find_all_two_distances(self, node): possible_nodes = [] for first_bit in range(0, len(node) - 1): for second_bit in range(1, len(node)): search_node = node.copy() first_bit_to_change = "0" if node[first_bit] == "1" else "1" second_bit_to_change = "0" if node[second_bit] == "1" else "1" search_node[first_bit] = first_bit_to_change search_node[second_bit] = second_bit_to_change if tuple(search_node) in self.union_find.node_leaders: possible_nodes.append(search_node) return possible_nodes def add_node(self, node): self.union_find.add_element(tuple(node)) one_distances = self.find_all_one_distances(node) for close_node in one_distances: self.one_distances.append((node, close_node)) two_distances = self.find_all_two_distances(node) for close_node in two_distances: self.two_distances.append((node, close_node)) def clusterfy(self): while len(self.one_distances) > 0 or len(self.two_distances) > 0: nodes = self.get_next_pair_of_nodes() leader1 = self.union_find.find(tuple(nodes[0])) leader2 = self.union_find.find(tuple(nodes[1])) if leader1 != leader2: self.union_find.union(tuple(leader1), tuple(leader2)) return len(self.union_find.clusters) def get_next_pair_of_nodes(self): if len(self.one_distances) > 0: return self.one_distances.pop() elif len(self.two_distances) > 0: return self.two_distances.pop() else: return None
def test_union(self): uf = UnionFind([i for i in range(0, 10)]) unions = [0, 2, 3, 3, 5, 5, 5, 5, 5, 5] for i, j in enumerate(unions): uf.union(i, j) self.assertEqual(uf.ids, [0, 1, 1, 1, 4, 4, 4, 4, 4, 4], msg='Union Find merge incorrect') self.assertEqual( uf.find(2), 1, msg='Union find incorrect finds the representative class')
def kruskal(edges, vertices): """ Runs the Kruskal algorithm using the edges and vertices. """ cost = 0 mst = [] n = len(vertices) # Sort the edges by weight. edges = sorted(edges, key=lambda x: x[1]) uf = UnionFind(vertices) for ((u, v), w) in edges: # If the edge doesn't create a circle if uf.find(u) != uf.find(v): # add it to the MST. uf.union(u, v) mst.append((u, v)) cost += w # Stop when the MST has |V|-1 edges. if len(mst) == n - 1: return cost, mst
def add_documents(name: str, event_ids: List[int], tweet_urls: Dict[int, models.URL], session): uf = UnionFind() tweets = session.query(models.Tweet).filter( models.Tweet.event_id_id.in_(event_ids)).all() for tweet in tqdm(tweets, desc="Iterating over tweets (create sets)"): uf.make_set(tweet.tweet_id) url_obj = tweet_urls.get(tweet.tweet_id) if url_obj: uf.make_set(url_obj.expanded_url) for tweet in tqdm(tweets, desc="Iterating over tweets (join sets)"): if tweet.in_reply_to_status_id: uf.union(tweet.tweet_id, int(tweet.in_reply_to_status_id)) if tweet.retweet_of_id: uf.union(tweet.tweet_id, int(tweet.retweet_of_id)) url_obj = tweet_urls.get(tweet.tweet_id) if url_obj: uf.union(tweet.tweet_id, url_obj.expanded_url) with session.begin(): group_doc = dict() groups = map(lambda g: str(uf.find(g)), uf.groups) for rep in groups: document = models.Document(url=rep) group_doc[rep] = document for tweet in tqdm(tweets, desc="Iterating over tweets (set documents)"): id = str(uf.find(tweet.tweet_id)) doc = group_doc[id] tweet.document = doc return uf
class UnionFind2: def __init__(self, groups, fn): self.fn = fn g = [] for group in groups: g.append(map(fn, group)) self.uf = UnionFind(g) def find(self, item): return self.uf.find(self.fn(item)) def union(self, item_1, item_2): self.uf.union(self.fn(item_1), self.fn(item_2)) def get_clusters(self): return self.uf.leader_to_group.values()
def kruskal(nodes:List(Int), edges:List(Tuple(Int, Int, Int)), edges_to_check:List(Tuple(Int, Int)))\ ->List(Tuple(Int, Int, Int)): sets = UnionFind({}) mst = [] for n in nodes: sets.add_node(n) for e in sorted(edges, key=itemgetter(2)): n1 = e[0] n2 = e[1] l1 = sets.find(n1) l2 = sets.find(n2) if l1 != l2: (e1, e2, w) = e if ((e1, e2) in edges_to_check) or (e2, e1) in edges_to_check: mst.append(e) sets.union(l1, l2) return mst
def test_find(self): uf = UnionFind([[1,2,3],[4,5],[6,7,8,9,0]]) self.assertEqual(uf.find(1), 1) self.assertEqual(uf.find(2), 1) self.assertEqual(uf.find(3), 1) self.assertEqual(uf.find(4), 4) self.assertEqual(uf.find(5), 4) self.assertEqual(uf.find(6), 6) self.assertEqual(uf.find(7), 6) self.assertEqual(uf.find(8), 6) self.assertEqual(uf.find(9), 6) self.assertEqual(uf.find(0), 6)
def accountsMerge(self, accounts): """ :type accounts: List[List[str]] :rtype: List[List[str]] """ email_to_id, id_to_name = self.create_mappings(accounts) uf = UnionFind(len(email_to_id)) # union emails within an account for account in accounts: p = email_to_id[account[1]] for i in range(2, len(account)): q = email_to_id[account[i]] uf.union(p, q) # collect emails by tree for email, p in email_to_id.iteritems(): parent = uf.find(p) id_to_emails[parent].append(email) return [[id_to_name[p]] + sorted(emails) for p, emails in id_to_emails.items()]
def smallestStringWithSwaps(self, s: str, pairs: List[List[int]]) -> str: n = len(s) uf = UnionFind(n) roots = [] for pair in pairs: uf.union(pair[0], pair[1]) # now we have the indices organized into connected components connected_components: DefaultDict[int, List[str]] = defaultdict(list) for i in range(n): roots.append(uf.find(i)) connected_components[roots[i]].append(s[i]) # we need to sort each connected component alphabetically for root, chars in connected_components.items(): connected_components[root] = sorted(chars) # now we can iterate through the string, find the root of each # index, and put the highest ranked element in that component # at that index smallest_str = [] for i in range(n): smallest_str.append(connected_components[roots[i]].pop(0)) return "".join(smallest_str)
def test_union_find(): uf = UnionFind(5) assert(uf.find(0) != uf.find(1)) assert(uf.find(0) == uf.find(0)) assert(uf.find(0) != uf.find(2)) assert(uf.n_subset == 5) uf.union(1, 0) assert(uf.is_same_subset(0, 1)) assert(not uf.is_same_subset(0, 2)) assert(uf.n_subset == 4) uf.union(2, 4) subsets = uf.get_subsets() expected_subsets = [{0, 1}, {2, 4}, {3}] assert(len(subsets) == len(expected_subsets)) for i in expected_subsets: assert(i in subsets) uf.union(2, 3) uf.union(3, 4) uf.union(0, 4) assert(uf.find(1) == uf.find(3)) assert(uf.n_subset == 1)
assert uf.nsets == 5 uf.union(0, 1) assert uf.nsets == 4 uf.union(2, 3) assert uf.nsets == 3 uf.union(4, 3) assert uf.nsets == 2 assert uf.connected(0, 3) == False assert uf.connected(4, 3) == True p_expected = [1, 1, 3, 3, 3] size_expected = [2, 2, 3, 3, 3] for i in range(5): assert uf.find(i) == p_expected[i] assert uf.set_size(i) == size_expected[i] uf.union(0, 3) assert uf.nsets == 1 p_expected = [3] * 5 size_expected = [5] * 5 for i in range(5): assert uf.find(i) == p_expected[i] assert uf.set_size(i) == size_expected[i]
is_prime = [ True ]*(n+1) def Furui(n): p = 0 is_prime[0] = False is_prime[1] = False for i in xrange(2, n+1): if is_prime[i]: prime[p] = i p += 1 for j in xrange(2*i, n+1, i): is_prime[j] = False return p p = Furui(n) if __name__ == '__main__': l = B - A + 1 U = UnionFind(l) for i in xrange(p): if prime[i] >= P: start = (A + prime[i] - 1) / prime[i] * prime[i] end = B / prime[i] * prime[i] for j in xrange(start, end+1, prime[i]): U.union(start-A, j-A) res = 0 for i in xrange(A, B+1): if (U.find(i-A) == i-A): res += 1 print res
(1, 1, 3), (2, 3, 1), (1, 5, 5), ] s = UnionFind(3*N) ans = 0 for i in xrange(K): t = info[i][0] x = info[i][1]-1 y = info[i][2]-1 if x < 0 or x >= N or y < 0 or y >= N: ans += 1 continue rx = s.find(x) ry = s.find(y) print rx, ry ry1 = s.find(y+N) ry2 = s.find(y+2*N) if t == 1: if rx == ry1 or rx == ry2: ans += 1 else: s.union(x, y) s.union(x + N, y + N) s.union(x+2*N, y+2*N) else: if rx == ry or rx == ry2: ans += 1 else: