0. Prim和Kruskal算法的区别
|
基本思想 |
时间复杂度 |
使用场景 |
Prim |
将顶点逐个加入集合,维护minDist[] ,贪心选择距离集合最近的顶点加入。 |
\(O(V^2)\) |
运行效率与节点数相关,与边数无关。适合稠密图。 |
Kruskal |
先对边进行排序;再选择连接不同分量的最短边(使用并查集 判断是否处于不同分量)。 |
\(O(ElogE)\) |
运行效率只与边数相关。适合稀疏图。 |
1. Prim算法(卡码网 53)
# 最小生成树prim算法
# 贪心地选择距离已有集合最小的边加入
def prim(graph) -> int:
result = 0
visited = [False for _ in range(len(graph))]
# 未选点距离已选集合的最短距离
minDist = [10001 for _ in range(len(graph))]
# 初始化:加入节点1
visited[1] = True
for i in range(2, len(minDist)):
minDist[i] = graph[1][i]
# 还要加入n-1个顶点
for i in range(len(minDist)-2):
node_to_add = -1
minVal = 10001
for j in range(2, len(minDist)):
if visited[j] == False and minDist[j] < minVal:
minVal = minDist[j]
node_to_add = j
# 将最近的未访问的节点加入集合
visited[node_to_add] = True
result += minVal
# 更新minDist数组
for j in range(2, len(minDist)):
if visited[j] == False and graph[node_to_add][j] < minDist[j]:
minDist[j] = graph[node_to_add][j]
return result
def main():
num_node, num_edge = map(int, input().split())
graph = [[10001 for _ in range(num_node+1)] for _ in range(num_node+1)]
for _ in range(num_edge):
node1, node2, val = map(int, input().split())
graph[node1][node2] = val
graph[node2][node1] = val
print(prim(graph))
if __name__ == "__main__":
main()
2. Kruskal算法(卡码网 53)
class Edge:
def __init__(self, node1, node2, val):
self.node1 = node1
self.node2 = node2
self.val = val
# 并查集
class UnionFindSet:
# 初始化并查集
def __init__(self, n):
self.father = list(range(n))
# 寻找本联通分量的根
def find(self, node1:int) -> int:
if node1 != self.father[node1]:
self.father[node1] = self.find(self.father[node1])
return self.father[node1]
def join(self, node1: int, node2: int):
root1 = self.find(node1)
root2 = self.find(node2)
if root1 != root2:
self.father[root2] = root1
def isSame(self, node1: int, node2: int):
return self.find(node1) == self.find(node2)
# 最小生成树 kruskal算法 选择连接不同分量的最短边
def kruskal(num_node, edges) -> int :
ufs = UnionFindSet(num_node + 1)
# 根据edge.val进行排序
edges.sort(key=lambda edge: edge.val)
result = 0
for e in edges:
if ufs.isSame(e.node1, e.node2) == False:
ufs.join(e.node1, e.node2)
result += e.val
return result
def main():
num_node, num_edge = map(int, input().split())
edges = []
for _ in range(num_edge):
node1, node2, val = map(int, input().split())
edges.append(Edge(node1, node2, val))
print(kruskal(num_node, edges))
if __name__ == "__main__":
main()