普利姆:
普利姆每次选取不在MST(最小生成树)中的点,直到图中所有点都在MST中,但它比较贪,所以选的点是离MST距离最近的点;由于选的是不在MST中的点,所以肯定不会有环。话不多说直接理步骤:
step1:初始化
- 创建visited标记MST中的节点
- 选择初始节点,并在visited中标记
n = len(graph)
visited = [False] * n
visited[start] = True
step2:选边
- 从在MST的节点出发,查找所有相邻边(查找在MST中的点的与不在MST中的邻居点的边),选出权重最小的
- 更新状态,重复上条步骤,直至,所有点包含在MST中
count = n - 1
while count:
count -= 1
min_edge = float('inf')
min_vertex = -1
for i in range(n):
for j in range(n):
if visited[i] and graph[i][j] > 0:
if not visited[j]:
if graph[i][j] < min_edge:
min_edge = graph[i][j]
min_vertex = j
# 想要总权重,就加最小权重看需求
# min_all += min_edge
if min_vertex == -1:
print("图不连通。")
break # 如果没有找到最小边,结束循环
# 更新状态
visited[min_vertex] = True
克鲁斯卡尔:
克鲁斯卡尔比较单纯好想,每一步选所有边中的最短边,但它有个问题,那就是因为是随机选的,不像prim一头在MST一头不在MST肯定不会有环;一般用并查集判断环,我的并查集写的比较简单,有强迫症的朋友想要加height的,勿喷;我是有需求才会用。
照旧,上步骤:
step1:初始化
- 每个点暂时都自立为王都是一个集合
- 把边抽出来
def find_father(x):
if x != father[x]:
father[x] = find_father(father[x])
return father[x]
def kruskal():
# 初始化
n = len(graph)
for i in range(n):
father[i] = i
edges = []
for i in range(n):
for j in range(n):
if graph[i][j] > 0:
edges.append((i, j, graph[i][j]))
edges.sort(key=lambda e: e[2], reverse=True) #按权重排序
step2:选边更新状态
- 选择权重最短的边,如果两节点不在一个集合,说明无环,加入,反之,不加入
- 当集合大小为图的大小时终止
# 选边
mst_edges = []
while edges:
# 这句判断可有可无,最后都会停下来
if len(mst_edges) == n - 1:
break
edge = edges.pop()
s = edge[0]
e = edge[1]
if find_father(s) != find_father(e): # 环的判断
father[s] = e # 合并到一个集合
mst_edges.append(edge)
完整代码:
def find_father(x):
if x != father[x]:
father[x] = find_father(father[x])
return father[x]
def kruskal():
# 初始化
n = len(graph)
for i in range(n):
father[i] = i
edges = []
for i in range(n):
for j in range(n):
if graph[i][j] > 0:
edges.append((i, j, graph[i][j]))
edges.sort(key=lambda e: e[2], reverse=True) #按权重排序
# 选边
mst_edges = []
while edges:
# 这句判断可有可无,最后都会停下来
if len(mst_edges) == n - 1:
break
edge = edges.pop()
s = edge[0]
e = edge[1]
if find_father(s) != find_father(e): # 环的判断
father[s] = e # 合并到一个集合
mst_edges.append(edge)
return mst_edges