class TestUnionFind(unittest.TestCase): def setUp(self): self.N = 10 self.uf = UF(self.N) self.pairs = ((0, 1), (1, 2), (4, 5), (7, 8), (8, 9)) def test_count(self): self.assertEqual(self.uf.count(), self.N) self.assertEqual(self.count_sets(), self.N) for x, y in self.pairs: self.uf.union(x, y) n = self.N - len(self.pairs) self.assertEqual(self.uf.count(), n) self.assertEqual(self.count_sets(), n) def test_find(self): for i in range(self.N): self.assertEqual(self.uf.find(i), i) for x, y in self.pairs: self.uf.union(x, y) for x, y in self.pairs: self.assertEqual(self.uf.find(x), self.uf.find(y)) def test_connected(self): for i in range(self.N): for j in range(self.N): if i == j: continue self.assertFalse(self.uf.connected(i, j)) for x, y in self.pairs: self.uf.union(x, y) for x, y in self.pairs: self.assertTrue(self.uf.connected(x, y)) def test_str_empty_uf(self): self.assertEqual(str(UF(0)), "") def test_str_uf(self): s = " ".join([str(x) for x in range(self.N)]) self.assertEqual(str(self.uf), s) def count_sets(self): return len(set([self.uf.find(x) for x in range(self.N)])) def tearDown(self): pass
def count_clusters(points, dist): n = len(points) uf = UnionFind(n) # compute all (dx,dy,dz,dt) such that abs(dx) + abs(dy) + abs(dz) + abs(dt) <= 3 # and don't include (0,0,0,0) DIRS = [(dx,dy,dz,dt) for dx in xrange(-dist, dist+1) \ for dy in xrange(-dist+abs(dx), dist+1-abs(dx)) \ for dz in xrange(-dist+abs(dx)+abs(dy), dist+1-abs(dx)-abs(dy)) \ for dt in xrange(-dist+abs(dx)+abs(dy)+abs(dz), dist+1-abs(dx)-abs(dy)-abs(dz)) \ if (dx,dy,dz,dt) != (0,0,0,0)] # generate a dict of each point to its index point_to_index = {p: i for i, p in enumerate(points)} # for each connected points, perform a union find between the indices of the two points for i in xrange(n): x, y, z, t = points[i] for dx, dy, dz, dt in DIRS: p2 = (x + dx, y + dy, z + dz, t + dt) if p2 in point_to_index: uf.union(i, point_to_index[p2]) # return the number of disjoint sets we found return uf.count()
def test_graph_2(): txs = [[1, 2, 3], [4, 5], [4, 6], [5, 7]] uf = UF(8) for tx in txs: parent = min(tx) for node in tx: uf.union(parent, node) print(uf.connected(5, 6)) print(uf.find(4)) print(uf.find(7)) print(uf.find(3)) return uf.count()
def compute_fuzzier(word): n = len(word) count = 0 cc = UF(n) G = nx.DiGraph() G.add_nodes_from(range(n)) max_positions = {0} max_value = word[0] unconsidered_positions = [i for i in range(n)] i = 0 j = 2 unconsidered_positions.remove(0) unconsidered_positions.remove(2) # Step 1: explore while cc.count() > 1: mp_list = list(max_positions) if cc.count() <= 3 and len(max_positions) > 1 and (mp_list[1] - mp_list[0]) > 1: i = mp_list[0] + 1 j = mp_list[1] + 1 while True: if j == n - 1 or i == mp_list[1]: max_positions = {mp_list[0]} i = mp_list[0] if len(unconsidered_positions) > 0: j = unconsidered_positions[len(unconsidered_positions) // 2] unconsidered_positions.remove(j) elif cc.count() > 1: for new_index in range(n): if cc.find(new_index) != cc.find(i): j = new_index break break count += 1 if i in unconsidered_positions: unconsidered_positions.remove(i) if j in unconsidered_positions: unconsidered_positions.remove(j) cc.union(i, j) if word[i] < word[j]: max_positions = {mp_list[1]} j = mp_list[1] if len(unconsidered_positions) > 0: i = unconsidered_positions[len(unconsidered_positions) // 2] unconsidered_positions.remove(i) elif cc.count() > 1: for new_index in range(n): if cc.find(new_index) != cc.find(j): i = new_index break elif word[i] > word[j]: max_positions = {mp_list[0]} i = mp_list[0] if len(unconsidered_positions) > 0: j = unconsidered_positions[len(unconsidered_positions) // 2] unconsidered_positions.remove(j) elif cc.count() > 1: for new_index in range(n): if cc.find(new_index) != cc.find(i): j = new_index break else: i += 1 j += 1 else: count += 1 cc.union(i, j) if word[i] < word[j]: G.add_edge(i, j) if word[j] > max_value: max_value = word[j] max_positions = {j} if len(unconsidered_positions) > 0: i = unconsidered_positions[len(unconsidered_positions) // 2] unconsidered_positions.remove(i) else: for new_index in range(n): if cc.find(new_index) != j: i = new_index break elif word[i] > word[j]: G.add_edge(j, i) if word[i] > max_value: max_value = word[i] max_positions = {i} if len(unconsidered_positions) > 0: j = unconsidered_positions[len(unconsidered_positions) // 2] unconsidered_positions.remove(j) elif cc.count() > 1: for new_index in range(n): if cc.find(new_index) != cc.find(i): j = new_index break else: G.add_edge(i, j) G.add_edge(j, i) if word[i] >= max_value: if i != n-1: max_positions.add(i) if j != n-1: max_positions.add(j) if len(unconsidered_positions) > 0: i = unconsidered_positions[0] unconsidered_positions.remove(i) elif cc.count() > 1: for new_index in range(n): if cc.find(new_index) != cc.find(j): i = new_index break if len(max_positions) == 1: return max_positions.pop(), count # Step 2 find max suffix from max occurences else: mp_list = list(set(max_positions)) mp_list.sort() mp_candidates = [mp_list[0]] longest_streak = 1 current_streak = 1 for i in range(len(mp_list) - 1): if mp_list[i + 1] - mp_list[i] == 1: # two consecutive maxima current_streak += 1 if current_streak > longest_streak: longest_streak = current_streak mp_candidates = [mp_list[i - current_streak + 2]] elif current_streak == longest_streak: mp_candidates.append(mp_list[i - current_streak + 2]) else: current_streak = 1 if current_streak == longest_streak: mp_candidates.append(mp_list[i + 1]) if len(mp_candidates) == 1: return mp_candidates.pop(), count elif mp_candidates[-1] == n - longest_streak: mp_candidates.remove(n - longest_streak) while len(mp_candidates) > 1: count += 1 i = mp_candidates.pop() j = mp_candidates.pop() if word[i + 1] > word[j + 1]: G.add_edge(j + 1, i + 1) mp_candidates.append(i) elif word[i + 1] < word[j + 1]: G.add_edge(i + 1, j + 1) mp_candidates.append(j) else: return j, count return mp_candidates.pop(), count