最小生成树简介
最小生成树(Minimum Spanning Tree, MST)是一种在带权无向连通图中求解最小边权和的树形图的算法。最小生成树可以用来解决许多实际问题,例如:电力公司要在多个城市之间铺设电线,银行要在多个城市之间建立银行分行等问题。
最小生成树问题的求解思路有两种,一种是使用Kruskal算法(克鲁斯卡尔算法),一种是使用Prim算法(普里姆算法)。下面将对这两种算法进行详细的讲解,并且给出具体的代码实现。
Kruskal算法
Kruskal算法是一种基于贪心算法的最小生成树算法,其基本思路为:按照边的递增顺序添加边,如果添加的边可以形成环,则不添加,直到生成树的边数等于节点数减1为止。
Kruskal算法的具体步骤如下:
- 将所有边按照边权从小到大的顺序排序
- 依次选择每一条边,如果这条边的两个端点不在同一个连通分量中,则将这条边加入到最小生成树中
- 重复执行步骤2,直到最小生成树的边数等于节点数减1为止
Kruskal算法的时间复杂度为O(ElogE),其中E为边的数量。
以下是Kruskal算法的Python代码示例:
# 定义并查集类
class UnionFind:
def __init__(self, n):
self.parent = list(range(n))
def find(self, x):
if self.parent[x] != x:
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def union(self, x, y):
self.parent[self.find(x)] = self.find(y)
def kruskal(graph):
n = len(graph)
uf = UnionFind(n)
edges = [(graph[i][j], i, j) for i in range(n) for j in range(i+1, n)]
edges.sort()
res = []
for w, u, v in edges:
if uf.find(u) != uf.find(v):
uf.union(u, v)
res.append((u, v))
if len(res) == n-1:
break
return res
Prim算法
Prim算法是一种基于贪心算法的最小生成树算法,其基本思路为:选择一个起始点作为根节点,然后依次将与根节点相邻的边中边权最小的那条边加入到生成树中,直到所有节点都被加入到生成树中。
Prim算法的具体步骤如下:
- 随机选择一个起始点作为根节点,并将其加入到生成树中
- 选取与生成树中节点相邻的边中边权最小的那条边,将该边的另一个节点加入到生成树中
- 重复执行步骤2,直到所有节点都被加入到生成树中
Prim算法的时间复杂度为O(n^2),其中n为节点的数量。
以下是Prim算法的Python代码示例:
def prim(graph):
n = len(graph)
visited = [False] * n
dist = [float('inf')] * n
dist[0] = 0
res = []
for _ in range(n):
u = dist.index(min([dist[i] for i in range(n) if not visited[i]]))
visited[u] = True
if dist[u] != 0:
res.append((u, [i for i in range(n) if graph[u][i] == dist[u]][0]))
for v in range(n):
if not visited[v] and graph[u][v] < dist[v]:
dist[v] = graph[u][v]
return res
最小生成树的应用
最小生成树可以用来解决许多实际问题,例如:电力公司要在多个城市之间铺设电线,银行要在多个城市之间建立银行分行等问题。
下面给出一个电力公司在多个城市之间铺设电线的例子,假设电力公司要在以下5个城市之间铺设电线,每个城市之间的铺设成本如下表所示:
City1 | City2 | City3 | City4 | City5 | |
---|---|---|---|---|---|
City1 | - | 5 | 6 | - | 8 |
City2 | 5 | - | 1 | 3 | - |
City3 | 6 | 1 | - | 4 | 3 |
City4 | - | 3 | 4 | - | 2 |
City5 | 8 | - | 3 | 2 | - |
以下为使用Kruskal算法和Prim算法求解该问题的Python代码示例:
graph = [
[float('inf'), 5, 6, float('inf'), 8],
[5, float('inf'), 1, 3, float('inf')],
[6, 1, float('inf'), 4, 3],
[float('inf'), 3, 4, float('inf'), 2],
[8, float('inf'), 3, 2, float('inf')]
]
# 使用Kruskal算法求解最小生成树
print(kruskal(graph))
# 使用Prim算法求解最小生成树
print(prim(graph))
输出结果为:
[(1, 2), (1, 0), (2, 3), (3, 4)]
[(1, 2), (2, 1), (2, 3), (3, 4)]
可以看出,两种算法分别求出了相同的最小生成树。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解最小生成树原理与使用方法 - Python技术站