📅  最后修改于: 2023-12-03 15:02:33.428000             🧑  作者: Mango
Kruskal算法是一种构建最小生成树的贪心算法,是由克鲁斯卡尔(J. Kruskal)在 1956 年发明的。Kruskal算法的主要思想是按照边的权值从小到大选取 n-1 条边,且这 n-1 条边不能形成环,最终构成一个最小生成树。在实际问题中,边的权值有可能重复。
邻接矩阵是一种常用的图的表示方法,其基本思想是用一个矩阵来表示一个图。对于 n 个点的图,邻接矩阵是一个 n × n 的矩阵,其元素值表示图中两个结点之间边的信息。当两个结点之间没有边时,对应的元素值为 0,否则为边的权值。
对于无向图(无向边),邻接矩阵是一个对称矩阵;对于有向图(有向边),邻接矩阵是一个非对称矩阵。
下面是 Kruskal算法在邻接矩阵上的简单实现,代码中使用了 Union-Find 数据结构来实现集合的合并和查找。
from typing import List, Tuple
def find(parent: List[int], i: int) -> int:
if parent[i] != i:
parent[i] = find(parent, parent[i])
return parent[i]
def union(parent: List[int], rank: List[int], x: int, y: int):
x_root = find(parent, x)
y_root = find(parent, y)
if x_root == y_root:
return
if rank[x_root] < rank[y_root]:
parent[x_root] = y_root
elif rank[x_root] > rank[y_root]:
parent[y_root] = x_root
else:
parent[y_root] = x_root
rank[x_root] += 1
def kruskal(n: int, edges: List[Tuple[int, int, int]]) -> List[Tuple[int, int, int]]:
parent = [i for i in range(n)]
rank = [0 for _ in range(n)]
result = []
edges.sort(key=lambda x: x[2]) # 按照边的权值从小到大排序
for edge in edges:
u, v, w = edge
if find(parent, u) != find(parent, v): # 判断是否形成环路
result.append(edge)
union(parent, rank, u, v) # 合并集合
return result
下面是一个测试示例:
n = 5
edges = [(0, 1, 2), (0, 3, 6), (1, 2, 3), (1, 3, 8), (1, 4, 5), (2, 4, 7), (3, 4, 9)]
print(kruskal(n, edges))
# 输出结果:[(0, 1, 2), (1, 2, 3), (1, 4, 5), (0, 3, 6)]
在上面的测试示例中,原始的图如下所示:
2 3
0-----1-----2
|\ / \ /|
| 5 7 |
| | | |
| 8 9 |
| v v |
| 4-->3--' |
'--------->'
运行 Kruskal算法后,得到的最小生成树如下所示(边的权值用数字表示):
2 3
0-----1-----2
| |
| |
5 7
|
4