class DijkSP(object):
	def __init__(self, G, s, t = None):
		"find the shortest path tree (in a directed graph with non-negative weights) from s to every other vertex using Dijkstra's alg"
		self._G = G
		self._s = s
		self._distTo = [_INF for _ in range(G.V())]
		self._distTo[s] = 0
		self._edgeTo = [_SENTINEL for _ in range(G.V())] # edgeTo[v]: last edge on shortest path from s to v
		self._pq = IndexMinPQ(G.V())
		self._pq.insert(s, 0)

		while (not self._pq.isEmpty()):
			v = self._pq.delMin() # add closest vertex to source to Tree
			if t and v == t:
				return
			self._relaxVertix(v)

	def distTo(self, v):
		"distance from src to vertex v"
		return self._distTo[v]

	def hasPathTo(self, v):
		"checks whether path exists from src to vertex v"
		return self._edgeTo[v] != _SENTINEL

	def pathTo(self, v):
		"returns path from src to vertex v"
		if not self.hasPathTo(v): return
		path = []
		e = self._edgeTo[v] 				# last edge of path
		while e.src() != self._s:
			path.append(e)
			e = self._edgeTo[e.src()]
		path.append(e)
		return path[::-1]

	def _relaxVertix(self, v):
		for e in self._G.adj(v):
			self._relaxEdge(e) # relaxEdge(e) updates the distTo and edgeTo data structures					

	def _relaxEdge(self, edge):
		"relaxes an edge by updating data structures with that edge"
		v = edge.src()
		w = edge.sink()
		if self._distTo[w] > self._distTo[v] + edge.weight():
			self._distTo[w] = self._distTo[v] + edge.weight() 			# distance to source
			self._edgeTo[w] = edge
			if not self._pq.contains(w):
					self._pq.insert(w, self._distTo[w])
			else: 
					self._pq.decreaseKey(w, self._distTo[w])

	def __repr__(self):
		"print spt built by Digjkstra object"
		V = len(self._edgeTo)
		spt = GraphLib.EdgeWeightedDigraph(V)
		for i in range(V):
			if self._edgeTo[i] != _SENTINEL:
				spt.addEdge(self._edgeTo[i])
		print str(spt.edges())
class DijkSP(object):
    def __init__(self, G, s, t=None):
        "find the shortest path tree (in a directed graph with non-negative weights) from s to every other vertex using Dijkstra's alg"
        self._s = s
        self._distTo = [_INF for _ in range(G.V())]
        self._distTo[s] = 0
        self._edgeTo = [_SENTINEL for _ in range(G.V())
                        ]  # edgeTo[v]: last edge on shortest path from s to v
        self._pq = IndexMinPQ(G.V())
        self._pq.insert(s, 0)

        while (not self._pq.isEmpty()):
            v = self._pq.delMin()  # add closest vertex to source to Tree
            if t and v == t: return
            for e in G.adj(v):
                self._relax(
                    e
                )  # relax(e) updates the distTo and edgeTo data structures

    def distTo(self, v):
        "distance from src to vertex v"
        return self._distTo[v]

    def hasPathTo(self, v):
        "checks whether path exists from src to vertex v"
        return self._edgeTo[v] != _SENTINEL

    def pathTo(self, v):
        "returns path from src to vertex v"
        if not self.hasPathTo(v): return
        path = []
        e = self._edgeTo[v]  # last edge of path
        while e.src() != self._s:
            path.append(e)
            e = self._edgeTo[e.src()]
        path.append(e)
        return path[::-1]

    def _relax(self, edge):
        "relaxes an edge by updating data structures with that edge"
        v = edge.src()
        w = edge.sink()
        if self._distTo[w] > self._distTo[v] + edge.weight():
            self._distTo[w] = self._distTo[v] + edge.weight(
            )  # distance to source
            self._edgeTo[w] = edge
            if not self._pq.contains(w):
                self._pq.insert(w, self._distTo[w])
            else:
                self._pq.decreaseKey(w, self._distTo[w])

    def __repr__(self):
        "print spt built by Digjkstra object"
        V = len(self._edgeTo)
        spt = GraphLib.EdgeWeightedDigraph(V)
        for i in range(V):
            if self._edgeTo[i] != _SENTINEL:
                spt.addEdge(self._edgeTo[i])
        print str(spt.edges())
class EagerPrimMST(object):
	'''
	similar to LazyPrimMST except remove obsolete edges from PQ
	given a connected, undirected, weighted graph, finds an MST and its weight
	key = vertex; priority = weight of edge
	PQ has 1 entry per vertex
	'''
	def __init__(self, EG):
		self._edgeTo = [-1 for _ in range(EG.V())]
		self._distTo = [_INF for _ in range(EG.V()) ]
		self._distTo[0] = 0
		self._pq = IndexMinPQ(EG.V())
		self._mst = [] 							# list of edges in MST
		self._weight = 0
		self._marked = set() 					# set of vertices in MST
		self._pq.insert(0, 0)

		while (not self._pq.isEmpty() and len(self._mst) < EG.V() - 1):
			v = self._pq.delMin()
			if v > 0:
				self._mst.append(self._edgeTo[v])
				self._weight += self._edgeTo[v].weight()
			self._visit(EG, v)

	def _visit(self, EG, v):
		'''
		add v to Tree; add all non-tree vertices adjacent to v to PQ; 
		update priority of edges connecting non-tree vertices to Tree
		'''
		self._marked.add(v)
		for e in EG.adj(v):
			# e is edge connecting w (non-Tree vertex) to Tree
			w = e.other(v)
			if w not in self._marked:
				if self._distTo[w] > e.weight():
					self._edgeTo[w] = e
					self._distTo[w] = e.weight()
					if not self._pq.contains(w):
						# w is not in PQ
						self._pq.insert(w, e.weight())
					else:
						self._pq.decreaseKey(w, e.weight())

	def mst(self):
		"returns edges in MST"
		return self._mst

	def weight(self):
		"returns weight of MST"
		return self._weight

	def __repr__(self):
			"Everything about MST"
			return "edges=%r wt=%r" % (self.mst(), self.weight())
class EagerPrimMST(object):
    '''
	similar to LazyPrimMST except remove obsolete edges from PQ
	given a connected, undirected, weighted graph, finds an MST and its weight
	key = vertex; priority = weight of edge
	PQ has 1 entry per vertex
	'''
    def __init__(self, EG):
        self._edgeTo = [-1 for _ in range(EG.V())]
        self._distTo = [_INF for _ in range(EG.V())]
        self._distTo[0] = 0
        self._pq = IndexMinPQ(EG.V())
        self._mst = []  # list of edges in MST
        self._weight = 0
        self._marked = set()  # set of vertices in MST
        self._pq.insert(0, 0)

        while (not self._pq.isEmpty() and len(self._mst) < EG.V() - 1):
            v = self._pq.delMin()
            if v > 0:
                self._mst.append(self._edgeTo[v])
                self._weight += self._edgeTo[v].weight()
            self._visit(EG, v)

    def _visit(self, EG, v):
        '''
		add v to Tree; add all non-tree vertices adjacent to v to PQ; 
		update priority of edges connecting non-tree vertices to Tree
		'''
        self._marked.add(v)
        for e in EG.adj(v):
            # e is edge connecting w (non-Tree vertex) to Tree
            w = e.other(v)
            if w not in self._marked:
                if self._distTo[w] > e.weight():
                    self._edgeTo[w] = e
                    self._distTo[w] = e.weight()
                    if not self._pq.contains(w):
                        # w is not in PQ
                        self._pq.insert(w, e.weight())
                    else:
                        self._pq.decreaseKey(w, e.weight())

    def mst(self):
        "returns edges in MST"
        return self._mst

    def weight(self):
        "returns weight of MST"
        return self._weight

    def __repr__(self):
        "Everything about MST"
        return "edges=%r wt=%r" % (self.mst(), self.weight())
    def __init__(self, EG):
        self._edgeTo = [-1 for _ in range(EG.V())]
        self._distTo = [_INF for _ in range(EG.V())]
        self._distTo[0] = 0
        self._pq = IndexMinPQ(EG.V())
        self._mst = []  # list of edges in MST
        self._weight = 0
        self._marked = set()  # set of vertices in MST
        self._pq.insert(0, 0)

        while (not self._pq.isEmpty() and len(self._mst) < EG.V() - 1):
            v = self._pq.delMin()
            if v > 0:
                self._mst.append(self._edgeTo[v])
                self._weight += self._edgeTo[v].weight()
            self._visit(EG, v)
    def __init__(self, G, s, t=None):
        "find the shortest path tree (in a directed graph with non-negative weights) from s to every other vertex using Dijkstra's alg"
        self._s = s
        self._distTo = [_INF for _ in range(G.V())]
        self._distTo[s] = 0
        self._edgeTo = [_SENTINEL for _ in range(G.V())
                        ]  # edgeTo[v]: last edge on shortest path from s to v
        self._pq = IndexMinPQ(G.V())
        self._pq.insert(s, 0)

        while (not self._pq.isEmpty()):
            v = self._pq.delMin()  # add closest vertex to source to Tree
            if t and v == t: return
            for e in G.adj(v):
                self._relax(
                    e
                )  # relax(e) updates the distTo and edgeTo data structures
	def __init__(self, G, s, t = None):
		"find the shortest path tree (in a directed graph with non-negative weights) from s to every other vertex using Dijkstra's alg"
		self._G = G
		self._s = s
		self._distTo = [_INF for _ in range(G.V())]
		self._distTo[s] = 0
		self._edgeTo = [_SENTINEL for _ in range(G.V())] # edgeTo[v]: last edge on shortest path from s to v
		self._pq = IndexMinPQ(G.V())
		self._pq.insert(s, 0)

		while (not self._pq.isEmpty()):
			v = self._pq.delMin() # add closest vertex to source to Tree
			if t and v == t:
				return
			self._relaxVertix(v)
	def __init__(self, EG):
		self._edgeTo = [-1 for _ in range(EG.V())]
		self._distTo = [_INF for _ in range(EG.V()) ]
		self._distTo[0] = 0
		self._pq = IndexMinPQ(EG.V())
		self._mst = [] 							# list of edges in MST
		self._weight = 0
		self._marked = set() 					# set of vertices in MST
		self._pq.insert(0, 0)

		while (not self._pq.isEmpty() and len(self._mst) < EG.V() - 1):
			v = self._pq.delMin()
			if v > 0:
				self._mst.append(self._edgeTo[v])
				self._weight += self._edgeTo[v].weight()
			self._visit(EG, v)