import heapq
class Solution:
def minimumCost(self, n: int, connections: List[List[int]]) -> int:
"""
main idea: MST (Prim)
tc O((E+V)*lgE + E) sc O(E+V)
1. build graph based on connections
2. create a priority queue, put any start point along with its cost in the queue to start
3. pop off one node, check if its not visited, update it to total cost
4. check current node's neighbour, if neighbour is not seen, push onto PQ
early termination: if total visited nodes == n, break
"""
g = collections.defaultdict(list)
seen = set()
for u,v,w in connections:
g[u].append((w,v))
g[v].append((w,u))
cost = 0
# cnt = 0
q = [(0,n)]# (cost, node_id)
#heapq.heappush(q,(0,n))
while q:
w,node = heapq.heappop(q)
if node not in seen:
seen.add(node)
cost += w
#cnt += 1
if len(seen) >= n :
break
for wei,nei in g[node]:
# pruning, reduce amount of vertices that already added into spanning tree
if nei not in seen:
heapq.heappush(q,(wei,nei)) # tc O(VlgE)
return cost if len(seen) == n else -1
Kruscal + UF
class UF:
def __init__(self,n):
self.parent = list(range(n))
self.rank = [1] *n
self.size = n
def find(self,x):
if x != self.parent[x]:
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def union(self, u, v):
pu,pv = self.find(u), self.find(v)
if pu == pv:
return False
if self.rank[pv] > self.rank[pu]:
self.parent[pu] = pv
self.rank[pu] += self.rank[pv]
else:
self.parent[pv] = pu
self.rank[pu] += self.rank[pv]
return True
class Solution:
def minimumCost(self, n: int, connections: List[List[int]]) -> int:
"""
tc O(ElgE + E) sc O(V)
1. sort the edges by weight
2. for each edge, find if two vertices belong to one UF, if not, join two points
3. each time union two vertices, reduce the uf size by one
4. early termination: if uf.size == 1, break
"""
uf = UF(n)
connections.sort(key = lambda x: x[2])
cost = 0
for u,v,w in connections:
if uf.union(u-1,v-1):
cost += w
uf.size -=1
if uf.size == 1:
break
return cost if uf.size == 1 else -1