概述
Kruskal算法
Kruskal算法核心在于对边按照权值排序,然后将不联通的边联通起来。需要借助并查集动态判断图是否联通。
- 找到最小生成树里的关键边和伪关键边
给你一个 n 个点的带权无向连通图,节点编号为 0 到 n-1 ,同时还有一个数组 edges ,其中 edges[i] = [fromi, toi, weighti] 表示在 fromi 和 toi 节点之间有一条带权无向边。最小生成树 (MST) 是给定图中边的一个子集,它连接了所有节点且没有环,而且这些边的权值和最小。
请你找到给定图中最小生成树的所有关键边和伪关键边。如果从图中删去某条边,会导致最小生成树的权值和增加,那么我们就说它是一条关键边。伪关键边则是可能会出现在某些最小生成树中但不会出现在所有最小生成树中的边。
请注意,你可以分别以任意顺序返回关键边的下标和伪关键边的下标。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree
分析:
判断关键边的标准为去掉该边后图不联通,或者去掉改变后最小生成树的权值和增加。判断图不联通可以通过并查集计数联通分量实现。
判断伪关键边的标准为优先添加此边,若最小生成树的权值和不变,则为伪关键边。判断之前需要排除它不是关键边。
参考解答:
class UnionFind:
def __init__(self, n) -> None:
self.f = list(range(n))
self.count = n
def find(self, p):
if self.f[p] != p:
self.f[p] = self.find(self.f[p])
return self.f[p]
def union(self, p, q):
pRoot = self.find(p)
qRoot = self.find(q)
if pRoot == qRoot:
return False
self.f[pRoot] = qRoot
self.count -= 1
return True
def getCount(self):
return self.count
class Solution:
def findCriticalAndPseudoCriticalEdges(self, n: int, edges: List[List[int]]) -> List[List[int]]:
m = len(edges)
for i, edge in enumerate(edges):
edge.append(i)
edges.sort(key=lambda x:x[2])
uf_std = UnionFind(n)
cost = 0
for edge in edges:
if uf_std.union(edge[0], edge[1]):
cost += edge[2]
ret = [list(), list()]
for i in range(m):
uf = UnionFind(n)
v = 0
for j in range(m):
if i != j and uf.union(edges[j][0], edges[j][1]):
v += edges[j][2]
if uf.getCount() != 1 or (uf.getCount() == 1 and v > cost):
ret[0].append(edges[i][3])
continue
uf = UnionFind(n)
uf.union(edges[i][0], edges[i][1])
v = edges[i][2]
for j in range(m):
if i != j and uf.union(edges[j][0], edges[j][1]):
v += edges[j][2]
if v == cost:
ret[1].append(edges[i][3])
return ret