Esempio n. 1
0
def test_connected():
	union = UnionFind(3)
	assert_equals(union.connected(0,1), False)
	assert_equals(union.connected(1,2), False)
	union.union(0,1)
	assert_equals(union.connected(0,1), True)
	assert_equals(union.connected(1,2), False)
	union.union(1,2)
	assert_equals(union.connected(2,0), True)
	assert_equals(union.connected(0,2), True)
	assert_equals(union.connected(1,2), True)
Esempio n. 2
0
    def test_tiny(self):
        uf = UnionFind(10)
        uf.union(4, 3)
        uf.union(3, 8)
        uf.union(6, 5)
        uf.union(9, 4)
        uf.union(2, 1)
        uf.union(5, 0)
        uf.union(7, 2)
        uf.union(6, 1)

        self.assertEqual(2, uf.count)
        self.assertTrue(uf.connected(2, 6))
        self.assertFalse(uf.connected(4, 5))
Esempio n. 3
0
    def test_tiny(self):
        uf = UnionFind(10)
        uf.union(4, 3)
        uf.union(3, 8)
        uf.union(6, 5)
        uf.union(9, 4)
        uf.union(2, 1)
        uf.union(5, 0)
        uf.union(7, 2)
        uf.union(6, 1)

        self.assertEqual(2, uf.count)
        self.assertTrue(uf.connected(2, 6))
        self.assertFalse(uf.connected(4, 5))
Esempio n. 4
0
    def __init__(self, graph):
        self.graph = graph
        self.pq = IndexMinPriorityQueue(graph.V)
        self.mst = []  # Empty list of edges

        # Build a priority queue
        for edge in graph.adjacent:
            # for edge in graph.adj(edges):
            self.pq.insert(edge, graph.adj(edge))

        union_find = UnionFind(graph.adjacent.keys())

        while not self.pq.isEmpty() and len(self.mst) < graph.V - 1:
            edges = self.pq.minIndex()
            self.pq.delMin()

            # Greedily add edges to MST
            for edge in edges:
                v = edge.either()
                w = edge.other(v)

                # Edge v-w does not create a cycle
                if not union_find.connected(v, w):
                    union_find.union(v, w)  # Merge sets
                    self.mst.append(edge)  # Add edge to MST
    def minCostToSupplyWater(self, n: int, wells: List[int],
                             pipes: List[List[int]]) -> int:
        # union find has size = n + 1 to accout for the virtual node
        uf = UnionFind(n + 1)
        total_cost = 0

        # add virtual node and connect it to each house with cost of
        # building a well in that house as its weight by appending
        # it to the pipes array
        for i, cost in enumerate(wells):
            pipes.append([n + 1, i + 1, cost])

        # sort the pipes array by weight ascending (Kruskal's algorithm)
        pipes_sorted = sorted(pipes, key=lambda pipe: pipe[2])

        for i, pipe in enumerate(pipes_sorted):

            # if all houses are connected we are done
            if uf.count == 1:
                break

            # if the houses connected by the pipe with the lowest weight
            #  are not connected, connect them via UnionFind.union and
            # add the cost of the pipe to total
            if not uf.connected(pipe[0] - 1, pipe[1] - 1):
                uf.union(pipe[0] - 1, pipe[1] - 1)
                total_cost += pipe[2]

        return total_cost
Esempio n. 6
0
 def validTree(self, n: int, edges: List[List[int]]) -> bool:
     uf = UnionFind(n)
     for edge in edges:
         if uf.connected(edge[0], edge[1]):
             return False
         uf.union(edge[0], edge[1])
     return uf.count == 1
Esempio n. 7
0
    def search(self):
        """search for MST"""

        # build pirority queue
        edge_queue = Queue.PriorityQueue()

        for e in self.G.edges():
            edge_queue.put((e.weight, e))

        uf = UnionFind(self.G.V())

        while not edge_queue.empty() and \
              len(self.edge_list) < self.G.V() - 1:

            # greedily add edges to MST
            _, e = edge_queue.get()
            v = e.either()
            w = e.other(v)

            # check if edge v-w not create cycle
            if not uf.connected(v, w):
                # merge sets
                uf.union(v, w)

                # add edge
                self.edge_list.append(e)
    def __mst(self):
        uf = UnionFind(self.graph.V())

        for edge in self.__sorted_edges():
            u, v, w = edge
            if not uf.connected(u, v):
                self.mst.append((u, v))
                uf.union(u, v)
                self.w += w
 def best_response(self, N, clib, croad, edges):
     sites = UnionFind(N)
     if croad >= clib: return N * clib
     fix_roads = 0
     for u, v in edges:
         i, j = u - 1, v - 1
         if sites.connected(i, j): continue
         sites.union(i, j)
         fix_roads += 1
     return fix_roads * croad + sites.count() * clib
Esempio n. 10
0
class Graph():

    """simple Graph class to run clustering algorithm"""

    def __init__(self, file_name):
        lines = self.get_edges_size(self.open_file(file_name))
        self.sorted_edges = tuple(sorted(self.process_line(lines),
                                         key=lambda edge: edge[2])
                                  )

    def open_file(self, file_name):
        """simple lines generator"""
        with open(file_name) as myfile:
            for line in myfile:
                yield line

    def get_edges_size(self, line_seq):
        """get the number of vertices as given in the first line of file
           setup the vertices as a tuple so we don't waste memory
           populate the __vertecies tuple with lists of tuples of vertex,cost
        """
        num_verticies = int(next(line_seq).split()[0])
        # next(line_seq)
        self._union_find = UnionFind(num_verticies)
        for line in line_seq:
            yield line

    def process_line(self, line_seq):
        for line in line_seq:
            types = (int, int, int)
            yield tuple(fun(val) for fun, val in zip(types, line.split()))

    def clustering(self):
        """ """
        edges = (val for val in self.sorted_edges)
        while self._union_find.sets > 4:
            edge = next(edges)
            if not self._union_find.connected(edge[0], edge[1]):
                self._union_find.union(edge[0], edge[1])
        while self._union_find.connected(edge[0], edge[1]):
            edge = next(edges)
        return edge
    def __cluster(self):

        uf = UnionFind(self.graph.V())

        min_spacing = 1e100

        for edge in self.__sorted_edges():

            u, v, w = edge

            if uf.count_components() > self.k and not uf.connected(u, v):
                uf.union(u, v)

            elif not uf.connected(u, v):
                # once we have k clusters,
                # examine each cross-clusters edge and pick the minimum
                if min_spacing > w:
                    min_spacing = w

        self.spacing = min_spacing
Esempio n. 12
0
def kruskal_mst(graph):
    union_find = UnionFind(graph.num_vertices)
    edges = sorted(graph.edges())

    for e in edges:
        v = e.either()
        w = e.other(v)

        if union_find.connected(v, w):
            continue

        union_find.union(v, w)
        yield e
Esempio n. 13
0
def main(argv):
    vtotal, vertices = construct(argv[0])

    vertices = sorted(vertices)
    uf       = UnionFind(vtotal)

    for i in xrange(vtotal):
        for j in xrange(i + 1, vtotal):
            if not uf.connected(vertices[i][1], vertices[j][1]):
                if hamming_distance(vertices[i][0], vertices[j][0]) <= 2:
                    uf.union(vertices[i][1], vertices[j][1])

    print
    print '%s clusters' % (uf.count())
    print
Esempio n. 14
0
def main(argv):
    vertices  = construct(argv[0])
    distances = generate_distances(24, 2) + generate_distances(24, 1)

    uf = UnionFind(len(vertices))

    for vertex in vertices:
        for distance in distances:
            candidate = vertex ^ distance
            if candidate in vertices:
                if not uf.connected(vertices[vertex], vertices[candidate]):
                    uf.union(vertices[vertex], vertices[candidate])

    print
    print '%s clusters' % (uf.count())
    print
Esempio n. 15
0
def karger_min_cut(G, edges):

    n = max(G.keys())
    cuts = UnionFind(n+1)

    edges_map = {}
    edges_index = 0
    for _ in xrange(n-2):
        edges_index = contract(G, edges, cuts, edges_index)
        #print G, edges

    assert(len(G) == 2)
    u, v = G.keys()
    #assert(len(G[u]) == len(G[v]))

    #before returning the cuts list, we must remove the self loops from the adjacency list 
    return filter(lambda (k, z): not cuts.connected(u, z), G[u])   #each edge is stored twice, so we can just return one of the two vertices' adj list
Esempio n. 16
0
def main(argv):
    vtotal, edges = construct_edges(argv[0])

    edges = sorted(edges)
    uf    = UnionFind(vtotal)
    k     = int(argv[1])
    T     = set([])

    max_spacing = 0
    while uf.count() >= k:
        edge = edges.pop(0)
        if not uf.connected(edge[1], edge[2]):
            uf.union(edge[1], edge[2])
            max_spacing = edge[0]

    print
    print 'For %s clustering: max spacing = %s' % (k, max_spacing)
    print
Esempio n. 17
0
class Graph():

    """simple Graph class to run Prim's MST algorithm"""

    def __init__(self, file_name):
        lines = self.get_edges_size(self.open_file(file_name))
        self.sorted_edges = tuple(sorted(self.process_line(lines),
                                         key=lambda edge: edge[2])
                                  )

    def open_file(self, file_name):
        """simple lines generator"""
        with open(file_name) as myfile:
            for line in myfile:
                yield line

    def get_edges_size(self, line_seq):
        """get the number of vertices as given in the first line of file
           setup the vertices as a tuple so we don't waste memory
           populate the __vertecies tuple with lists of tuples of vertex,cost
        """
        num_verticies = int(next(line_seq).split()[0])
        next(line_seq)
        self.__union_find = UnionFind(num_verticies)
        for line in line_seq:
            yield line

    def process_line(self, line_seq):
        for line in line_seq:
            types = (int, int, float)
            yield tuple(fun(val) for fun, val in zip(types, line.split()))

    def kruskal_mst(self):
        """pick a random start_vertex then extract from heap until empty"""
        total_cost = 0
        edges = (val for val in self.sorted_edges)
        while self.__union_find.sets > 1:
            edge = next(edges)
            if self.__union_find.connected(edge[0], edge[1]):
                continue
            total_cost += edge[2]
            self.__union_find.union(edge[0], edge[1])
        return total_cost
Esempio n. 18
0
def karger_min_cut(G, edges):

    n = max(G.keys())
    cuts = UnionFind(n + 1)

    edges_map = {}
    edges_index = 0
    for _ in xrange(n - 2):
        edges_index = contract(G, edges, cuts, edges_index)
        #print G, edges

    assert (len(G) == 2)
    u, v = G.keys()
    #assert(len(G[u]) == len(G[v]))

    #before returning the cuts list, we must remove the self loops from the adjacency list
    return filter(
        lambda (k, z): not cuts.connected(u, z), G[u]
    )  #each edge is stored twice, so we can just return one of the two vertices' adj list
Esempio n. 19
0
    def solve(self, board: List[List[str]]) -> None:
        if not board:
            return

        n_rows = len(board)
        n_cols = len(board[0])

        if n_rows < 3 or n_cols < 3:
            return

        dummy = n_rows * n_cols  # index for dummy node
        #uf = SimpleUnionFind(dummy + 1)
        uf = UnionFind(dummy + 1)

        for r in range(n_rows):
            for c in range(n_cols):
                if board[r][c] == 'O':
                    i = r * n_cols + c

                    # Connect border 'O' cells to dummy node.
                    if r in (0, n_rows - 1) or c in (0, n_cols - 1):
                        uf.union(i, dummy)
                    else:  # connect interior 'O' cells to neighbor 'O' cells
                        if board[r - 1][c] == 'O':
                            uf.union(i, i - n_cols)
                        if board[r + 1][c] == 'O':
                            uf.union(i, i + n_cols)
                        if board[r][c - 1] == 'O':
                            uf.union(i, i - 1)
                        if board[r][c + 1] == 'O':
                            uf.union(i, i + 1)

        for r in range(1, n_rows - 1):
            for c in range(1, n_cols - 1):
                if board[r][c] == 'O' and not uf.connected(
                        r * n_cols + c, dummy):
                    board[r][c] = 'X'
Esempio n. 20
0
#! /usr/bin/python

import sys
from union_find import UnionFind

if __name__ == '__main__':
    num_of_node = int(sys.stdin.readline())
    edge_coll = []
    for line in sys.stdin.readlines():
        a, b, cost = line.split()
        edge_coll.append((int(cost), int(a) - 1, int(b) - 1))

    edge_coll.sort(lambda x, y: x[0] - y[0])

    union_find = UnionFind(num_of_node)
    expected_cluster_size = 4
    for edge in edge_coll:
        cost, x, y = edge
        union_find.union(x, y)
        if union_find.num_of_cluster == expected_cluster_size:
            break

    max_clustering_map = {}
#a    print union_find.coll
    for edge in edge_coll:
        cost, x, y = edge
        if not union_find.connected(x, y):
            print cost
            break
Esempio n. 21
0
from union_find import UnionFind

if __name__ == "__main__":
    connections = [[4, 3], [3, 8], [6, 5], [9, 4], [2, 1], [8, 9], \
        [5, 0], [7, 2], [6, 1], [1, 0], [6, 7]]

    nodes = set([node for links in connections for node in links])

    union_find = UnionFind(nodes)

    for link in connections:
        p = link[0]
        q = link[1]

        if not union_find.connected(p, q):
            union_find.union(p, q)
            print str(p) + " " + str(q)

    print union_find.connected(0, 1) # (0, 8)
class PercolationGrid:
    '''
  - percolation system model: n-by-n grid of cells. 
    - each cell (r, c) :  unblocked or blocked. 
    - top left cell: cell(1, 1) 
    - bottom right cell: cell(n, n) 
  - A system percolates if:
    - we fill all unblocked cells connected to the top row
    and that process fills some open cell on the bottom row.
  '''
    def __init__(self, n):
        '''Creates an n x n grid, with all cells blocked initially'''
        self.n = n
        self.cell_count = n * n
        self.unblocked_cell_count = 0

        # Each cell has a corresponding node number IE
        # cell at row = 1, column = 1 -> node = 1
        # cell at row = 1, column = 2 -> node = 2
        # cell at row = 2, column = n -> node = 2 * n
        # cell at row = n, column = n -> node = n * n
        # - node 0 - connects to open all top row cells
        # - node n*n + 1 - connects to  all open bottom row cells
        self.node_count = self.cell_count + 2

        # Initializes a Tree object that:
        # - Efficiently connects two cells
        # - Efficiently finds if two cells are connected
        # Each cell represented as a node (number)
        self.UFTree = UnionFind(self.node_count)

        # List index: node(number)
        # Corresponding value: unblocked(True), blocked(False)
        # Initially, all nodes (cells) are blocked
        self.is_node_unblocked = [False for i in range(self.node_count)]

        # Unblock virtual top and virtual bottom nodes
        # So nodes can connect with it
        self.is_node_unblocked[0] = True
        self.is_node_unblocked[-1] = True

    def unblocked_cells_fraction(self):
        '''Number of unblocked cells over total number of cells'''
        return self.unblocked_cell_count / self.cell_count

    def does_percolate(self):
        ''' 
    Is there a path from the cells in the top row to 
    the cells in the bottom row? 
    '''
        return self.UFTree.connected(0, self.cell_count + 1)

    def is_cell_unblocked(self, r, c):
        '''Is cell unblocked?'''
        i = self.node_given_cell(r, c)
        return self.is_node_unblocked[i]

    def unblock_cell(self, r, c):
        '''
    Unblock cell at row r and column c, if blocked.
    Connect this cell to all open neighboring nodes
    '''
        # make sure that values given makes sense
        self.check_scope(r, c)
        # get node representation of cell
        current = self.node_given_cell(r, c)
        # don't do anything, if the given cell's unblocked
        if self.is_node_unblocked[current] is True: return
        # mark node as unblocked
        self.is_node_unblocked[current] = True
        # remember to update the running unblocked cell total
        self.unblocked_cell_count += 1
        # connect the node to its neighbors
        self.connect_unblocked_neighbors(current, r, c)

    def connect_unblocked_neighbors(self, current, r, c):
        '''
    Given: node number `current` at grid cell location (`r`, `c`)
    Connect the node to its left, right, top, and bottom 
    neighbors given they exist and are not blocked
    '''

        # connect node current to its left and right neighbors
        if c != 1:
            left = self.node_given_cell(r, c - 1)
            self.connect_nodes(current, left)
        if c != self.n:
            right = self.node_given_cell(r, c + 1)
            self.connect_nodes(current, right)

        # connect node to its top and bottom neighbors
        # if the node is at the most top row connect it to
        # the "virtual top node"
        # if the node is at the most bottom row, connect it to
        # the "virtual bottom node"
        top, bottom = 0, -1

        if r != 1: top = self.node_given_cell(r - 1, c)
        if r != self.n: bottom = self.node_given_cell(r + 1, c)

        self.connect_nodes(current, top)
        self.connect_nodes(current, bottom)

    def connect_nodes(self, i, j):
        '''Connect two node i, j if both nodes are unblocked'''
        if self.is_node_unblocked[i] and self.is_node_unblocked[j]:
            self.UFTree.union(i, j)

    def node_given_cell(self, r, c):
        '''Node representing cell located at row r, column c'''
        return (r - 1) * self.n + c

    def cell_given_node(self, i):
        '''Location tuple, (row, column) representing cell
       that corresponds to node i'''
        r, c = divmod(i - 1, self.n)
        return r + 1, c + 1

    def are_connected(self, m, n):
        '''Are cells m(r1, c1) and n(r2, c2) connected?'''
        (x, y), (i, j) = m, n
        a, b = self.node_given_cell(x, y), self.node_given_cell(i, j)
        return self.UFTree.connected(a, b)

    def check_scope(self, r, c):
        '''
    Assert error if either row or column is
    incorrect type or not within range 
    '''
        out_of_scope_message = "%r ...Not between 0 and " + str(self.n)
        c_message = "c: " + out_of_scope_message
        r_message = "r: " + out_of_scope_message

        assert type(r) is int, "r: %r ...Not an integer" % r
        assert type(c) is int, "c: %r ...Not an integer" % c
        assert 0 < c <= self.n, c_message % r
        assert 0 < r <= self.n, r_message % r
Esempio n. 23
0
uf = UnionFind(5)

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]
Esempio n. 24
0
    if random.choices([False, True], weights=[100 * (1 - P), 100 * P])[0]:
        mat[i] = " "
        # First ROW
        if X > i >= 0:
            uf.union(i, X * Y)
        elif X * (Y - 1) <= i < X * Y:
            # print(i)
            uf.union(i, X * Y + 1)
            # Above Row
            if i - X > 0 and mat[i - X] == " ":
                uf.union(i, i - X)
        else:
            # Above Row
            if i - X > 0 and mat[i - X] == " ":
                uf.union(i, i - X )

            # Left Block
            if i - 1 > 0 and int((i - 1) / X) == int(i / X) and mat[i - 1] == " ":
                uf.union(i, i - 1)

print("\n".join(["".join(mat[i * X: i * X + X]) for i in range(Y)]))
print(uf.connected(X*Y, X * Y + 1, display=True))
print()
# while (k := input()) != "n":
#     print(uf.connected(0, int(k) + 1, display=True))
# input()
# for x in range(X):
#     for y in range(Y):
#         print(mat[x][y], end="")
#     print()