Example #1
0
def diameter(G):
    marked = [False] * G.V()
    edge_to = [None] * G.V()
    q = Queue()

    marked[0] = True
    q.enqueue(0)

    while not q.is_empty():
        v = q.dequeue()
        for adj in G.adj(v):
            if marked[adj] == False:
                marked[adj] = True
                edge_to[adj] = v
                q.enqueue(adj)

    # compute dist of all paths
    paths = []
    for i in range(G.V()):
        dist = 0
        curr = i
        while edge_to[curr] != None:
            dist += 1
            curr = edge_to[curr]

        paths.append(dist)

    return max(paths)
 def _bfs(self, G, s):
     # breadth-first search from a single source
     queue = Queue()
     self._marked[s] = True  # Mark the source
     queue.enqueue(s)  # and put it on the queue.
     while not queue.is_empty():
         v = queue.dequeue()  # Remove next vertex from the queue.
         for w in G.adj(v):
             if not self._marked[w]:
                 self._edgeTo[w] = v  # For every unmarked adjacent vertex,
                 self._marked[w] = True  # mark it because path is known,
                 queue.enqueue(w)  # and add it to the queue.
Example #3
0
    def bfs(self, G, s):
        # mark source node and insert into queue to initialise bfs
        self._marked[s] = True
        q = Queue()
        q.enqueue(s)

        # continue bfs until queue is empty (all reachable nodes have been visited)
        while q.is_empty() == False:
            s = q.dequeue()
            for adj in G.adj(s):
                if self._marked[adj] == False:
                    self._marked[adj] = True
                    q.enqueue(adj)
                    self._count += 1
Example #4
0
    def can_be_colored(self, src):
        coloring = [-1] * self._V

        for src in range(self._V):
            if coloring[src] == -1:
                coloring[src] = 1

                # Create a queue (FIFO) of vertex numbers and
                # enqueue source vertex for BFS traversal
                q = Queue()
                q.enqueue(src)

                # Run while there are vertices in queue
                # (Similar to BFS)
                while q.is_empty() == False:
                    u = q.dequeue()
                    for edge in self.adj(u):
                        start = u
                        for possibility in [edge.start(), edge.end()]:
                            if possibility != u:
                                end = possibility

                        # adjacent not visited yet
                        if coloring[end] == -1:
                            if edge.type() == 0:  # harmony
                                coloring[end] = coloring[start]

                            elif edge.type() == 1:  # conflict
                                if coloring[start] == 0:
                                    coloring[end] = 1
                                elif coloring[start] == 1:
                                    coloring[end] = 0
                            q.enqueue(end)
                            continue
                        if edge.type() == 0:  # harmony
                            # print(coloring[edge.start()], coloring[edge.end()])
                            if coloring[start] != coloring[end]:
                                return 0
                        elif edge.type() == 1:  # conflict
                            # print(coloring[edge.start()], coloring[edge.end()])
                            if coloring[start] == coloring[end]:
                                return 0
        return 1
Example #5
0
    def _bfs(self, G: Graph, s: int):
        """
        bfs to search for shortest path from source s to all vertex

        :param G:
        :param s:
        :return:
        """
        queue = Queue()
        self._dist_to[s] = 0
        self._edgeTo[s] = 0
        self._marked[s] = True
        queue.enqueue(s)

        while not queue.is_empty():
            v = queue.dequeue()
            for w in G.adj(v):
                if not self._marked[w]:
                    self._marked[w] = True
                    self._edgeTo[w] = v
                    self._dist_to[w] = self._dist_to[v] + 1
                    queue.enqueue(w)
Example #6
0
    def build_fail(self):
        """

        build the fail pointer for each node.
        fail pointer is the longest suffix which can match the other's prefix,最长可匹配后缀
        and the pointer points to the prefix's last node.
        the building idea is like reversion.

        1.pc(p's child)'s fail is qc:  pc=qc when pc.data==qc.data. q =p.fail
        2.root's fail is none
        BFS the AcTrie and build fail for each node get from queue.

        :return:
        """
        queue = Queue()
        self._root.fail = None
        queue.enqueue(self._root)

        while not queue.is_empty():
            p = queue.dequeue()
            # BFS traverse the trie,each time set the p'c child pc's fail when p's fail is known.
            for pc in p.children:
                if pc is None:
                    continue
                if pc == self._root:
                    pc.fail = self._root
                else:
                    q = p.fail
                    while q:
                        # qc is the q'child which has same char with pc.
                        qc = q.children[ord(pc.data)]
                        if qc:
                            pc.fail = qc
                            break
                        # if qc not exist, q=q.fail, repeat.
                        q = q.fail
                    if q is None:
                        pc.fail = self._root
                queue.enqueue(pc)
def solve(world, R, L):
    # find starting indices
    start_from = []
    for j in range(R):
        if world[j][0] == 'P':
            start_from.append((j, 1))

    # dijkstra shortest path finding from starting positions to the right
    min_distances = []
    for index in start_from:
        i, j = index
        # built dist_to array
        dist_to = []
        for _ in range(R):
            line = []
            for _ in range(L):
                line.append(math.inf)
            dist_to.append(line)

        # intialise starting position
        dist_to[i][j] = int(world[i][j])
        q = Queue()
        q.enqueue((i, j))

        while not q.is_empty():
            v = q.dequeue()  # dequeue current index
            for adj in adjacents(R, L, v[0], v[1]):
                i, j = adj[0], adj[1]
                if world[i][j] in ['P', 'U', 'M', 'A', '.']:
                    # print(f'found: {world[i][j]}')
                    continue
                else:
                    # if distance can be decreased, decrease
                    if dist_to[i][j] > int(world[i][j]) + dist_to[v[0]][v[1]]:
                        dist_to[i][j] = int(world[i][j]) + dist_to[v[0]][v[1]]
                        q.enqueue(adj)
        min_distances.append(min([dist_to[i][L-2] for i in range(R)]))

    return min(min_distances)
Example #8
0
def solve(R, C, world):
    flat_world = [item for sublist in world for item in sublist]
    G = Graph(len(flat_world))

    # add horizontal edges
    for i in range(R):
        for j in range(C - 1):
            G.add_edge(j + (i * C), j + (i * C) + 1)
    # add vertical edges
    for i in range(R - 1):
        for j in range(C):
            G.add_edge(j + (i * C), j + (i * C) + C)

    # create mapping
    mapping = {i: flat_world[i] for i in range(len(flat_world))}
    # print(G)
    # print(mapping)

    # find virus and make it source
    s = 0
    for x in flat_world:
        if x == 2:
            break
        s += 1

    # start bfs from infection
    q = Queue()
    q.enqueue(s)

    while q.is_empty() == False:
        v = q.dequeue()
        for adj in G.adj(v):
            if mapping[adj] == 1:  # land
                mapping[adj] = 2  # infect the land
                q.enqueue(adj)
            elif mapping[adj] == 3:  # encounter human
                return 1
    return 0
Example #9
0
def shortest_path(G, u, v):
    marked = [False] * G.V()
    edge_to = [None] * G.V()

    q = Queue()
    marked[u] = True
    q.enqueue(u)

    while not q.is_empty():
        s = q.dequeue()
        for adj in G.adj(s):
            if not marked[adj]:
                marked[s] = True
                edge_to[adj] = s
                q.enqueue(adj)

    dist = 0
    curr = v
    while edge_to[curr] != None:
        dist += 1
        curr = edge_to[curr]

    return dist
Example #10
0
def solve(R, C, world):
    # find virus and make it source
    s = None
    for i in range(R):
        for j in range(C):
            if world[i][j] == 2:
                s = (i, j)

    # start bfs from infection
    q = Queue()
    q.enqueue(s)

    while q.is_empty() == False:
        v = q.dequeue()
        # for row in world:
        #    print(row)
        # print('\n')
        for adj in adjacents(world, v[0], v[1]):
            if world[adj[0]][adj[1]] == 1:
                world[adj[0]][adj[1]] = 2
                q.enqueue(adj)
            elif world[adj[0]][adj[1]] == 3:
                return 1
    return 0
Example #11
0
class BellmanFordSP:
    # Computes a shortest paths tree from s to every other vertex in
    # the edge-weighted digraph G.
    # @param G the acyclic digraph
    # @param s the source vertex
    # @throws IllegalArgumentException unless 0 <= s < V
    def __init__(self, G, s):
        self._distTo = [sys.float_info.max
                        ] * G.V()  #distTo[v] = distance  of shortest s->v path
        self._edgeTo = [None
                        ] * G.V()  #edgeTo[v] = last edge on shortest s->v path
        self._onQueue = [False
                         ] * G.V()  #onQueue[v] = is v currently on the queue?
        self._queue = Queue()  #queue of vertices to relax
        self._cost = 0  #number of calls to relax()
        self._cycle = None  #negative cycle (or None if no such cycle)

        #Bellman-Ford algorithm
        self._distTo[s] = 0.0
        self._queue.enqueue(s)
        self._onQueue[s] = True
        while not self._queue.is_empty() and not self.has_negative_cycle():
            v = self._queue.dequeue()
            self._onQueue[v] = False
            self._relax(G, v)
        assert self._check(G, s)

    #relax vertex v and put other endpoints on queue if changed
    def _relax(self, G, v):
        for e in G.adj(v):
            w = e.to_vertex()
            if self._distTo[w] > self._distTo[v] + e.weight():
                self._distTo[w] = self._distTo[v] + e.weight()
                self._edgeTo[w] = e
                if not self._onQueue[w]:
                    self._queue.enqueue(w)
                    self._onQueue[w] = True
            if self._cost % G.V() == 0:
                self._find_negative_cycle()
                if self.has_negative_cycle():
                    return  #found a negative cycle
            self._cost += 1

    # Is there a negative cycle reachable from the source vertex s?
    # @return true if there is a negative cycle reachable from the
    #    source vertex s, and false otherwise
    def has_negative_cycle(self):
        return self._cycle is not None

    # Returns a negative cycle reachable from the source vertex s, or None
    # if there is no such cycle.
    # @return a negative cycle reachable from the soruce vertex s
    #    as an iterable of edges, and None if there is no such cycle
    def negative_cycle(self):
        return self._cycle

    #by finding a cycle in predecessor graph
    def _find_negative_cycle(self):
        V = len(self._edgeTo)
        spt = EdgeWeightedDigraph(V)
        for v in range(V):
            if self._edgeTo[v] is not None:
                spt.add_edge(self._edgeTo[v])

        finder = EdgeWeightedDirectedCycle(spt)
        self._cycle = finder.cycle()

    # Returns the length of a shortest path from the source vertex s to vertex v.
    # @param  v the destination vertex
    # @return the length of a shortest path from the source vertex s to vertex v;
    #         sys.float_info.max if no such path
    # @throws UnsupportedOperationException if there is a negative cost cycle reachable
    #         from the source vertex s
    # @throws IllegalArgumentException unless 0 <= v < V
    def dist_to(self, v):
        self._validate_vertex(v)
        if self.has_negative_cycle():
            raise UnsupportedOperationException("Negative cost cycle exists")
        return self._distTo[v]

    # Is there a path from the source s to vertex v?
    # @param  v the destination vertex
    # @return true if there is a path from the source vertex
    #         s to vertex v, and false otherwise
    # @throws IllegalArgumentException unless 0 <= v < V
    def has_path_to(self, v):
        self._validate_vertex(v)
        return self._distTo[v] < sys.float_info.max

    # Returns a shortest path from the source s to vertex v.
    # @param  v the destination vertex
    # @return a shortest path from the source s to vertex v
    #         as an iterable of edges, and None if no such path
    # @throws UnsupportedOperationException if there is a negative cost cycle reachable
    #         from the source vertex s
    # @throws IllegalArgumentException unless 0 <= v < V
    def path_to(self, v):
        self._validate_vertex(v)
        if self.has_negative_cycle():
            raise UnsupportedOperationException("Negative cost cycle exists")
        if not self.has_path_to(v): return None
        path = Stack()
        e = self._edgeTo[v]
        while e is not None:
            path.push(e)
            e = self._edgeTo[e.from_vertex()]
        return path

    #check optimality conditions: either
    #(i) there exists a negative cycle reacheable from s
    #    or
    #(ii)  for all edges e = v->w:            distTo[w] <= distTo[v] + e.weight()
    #(ii') for all edges e = v->w on the SPT: distTo[w] == distTo[v] + e.weight()
    def _check(self, G, s):

        #has a negative cycle
        if self.has_negative_cycle():
            weight = 0.0
            for e in self.negative_cycle():
                weight += e.weight()
            if weight >= 0.0:
                print("error: weight of negative cycle = {}".format(weight))
                return False

        #no negative cycle reachable from source
        else:

            #check that distTo[v] and edgeTo[v] are consistent
            if self._distTo[s] != 0.0 or self._edgeTo[s] is not None:
                print("distanceTo[s] and edgeTo[s] inconsistent")
                return False

            for v in range(G.V()):
                if v == s: continue
                if self._edgeTo[v] is None and self._distTo[
                        v] != sys.float_info.max:
                    print("distTo[] and edgeTo[] inconsistent")
                    return False

            #check that all edges e = v->w satisfy distTo[w] <= distTo[v] + e.weight()
            for v in range(G.V()):
                for e in G.adj(v):
                    w = e.to_vertex()
                    if self._distTo[v] + e.weight() < self._distTo[w]:
                        print("edge {} not relaxed".format(e))
                        return False

            #check that all edges e = v->w on SPT satisfy distTo[w] == distTo[v] + e.weight()
            for w in range(G.V()):
                if self._edgeTo[w] is None: continue
                e = self._edgeTo[w]
                v = e.from_vertex()
                if w != e.to_vertex(): return False
                if self._distTo[v] + e.weight() != self._distTo[w]:
                    print("edge {} on shortest path not tight".format(e))
                    return False

        print("Satisfies optimality conditions")
        print()
        return True

    #raise an IllegalArgumentException unless 0 <= v < V
    def _validate_vertex(self, v):
        V = len(self._distTo)
        if v < 0 or v >= V:
            raise IllegalArgumentException(
                "vertex {} is not between 0 and {}".format(v, V - 1))
def connected_inhabitans_multiworld(L):
    # intialise graph object with V vertices
    R = len(L[0])
    C = len(L)

    flat_L = [item for sublist in L for item in sublist]
    V = len(flat_L)
    G = AdjacencyListGraph(V)

    # add horizontal edges
    for i in range(R - 1):
        for j in range(C):
            G.add_edge(i + (R * j), i + (R * j) + 1)
    # add right diagonal edges
    for i in range(R):
        for j in range(C - 1):
            if j % 2 == 0:
                G.add_edge(i + (R * j), i + (R * j) + R)
            else:
                if i >= R - 1:
                    break
                G.add_edge(i + (R * j), i + (R * j) + R + 1)

    # add left diagonal edges
    for i in range(R):
        for j in range(C - 1):
            if j % 2 == 0:
                if i == 0:
                    continue
                G.add_edge(i + (R * j), i + (R * j) + R - 1)
            else:
                G.add_edge(i + (R * j), i + (R * j) + R)

    print(G)
    # create mapping
    mapping = {i: flat_L[i] for i in range(len(flat_L))}
    print(mapping)

    # find source
    s = 0
    for x in flat_L:
        if x == 0:
            break
        s += 1

    d = 0
    while True:
        print(d, mapping)
        # total number of grass fields
        total_count = len([x for x in mapping.values() if x == 0])

        marked = [False] * G.V()
        q = Queue()
        count = 1
        marked[s] = True
        q.enqueue(s)

        while q.is_empty() == False:
            v = q.dequeue()
            for adj in G.adj(v):
                if marked[adj] == False and mapping[adj] == 0:
                    marked[adj] = True
                    q.enqueue(adj)
                    count += 1

        print(total_count, count)

        if count == total_count:
            return d

        # base case (no more lowering of water possible)
        if len([x for x in mapping.values() if x > 0]) == 0:
            return 'impossible'

        d += 1
        for i in range(len(mapping)):
            if mapping[i] > 0:
                mapping[i] -= 1