所有生成树中,边总权和最小的生成树称为G的最小生成树(Minimum Spanning Tree, MST)。最小生成树的常用算法有Prim算法(适用于稠密图)、Kruskal算法(贪心思想,适用于稀疏图)。在实际应用中,许多问题的图论模型都是最小生成树,如通信网络建设、有线电缆铺设、加工设备分组等。
1. NetworkX
直接调NetworkX的API
- 代码
import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
# 邻接矩阵,0表示不邻接
adj_arr = np.array([[0, 7, 0, 0, 0, 5],
[7, 0, 9, 0, 3, 0],
[0, 9, 0, 6, 0, 0],
[0, 0, 6, 0, 8, 10],
[0, 3, 0, 8, 0, 4],
[5, 0, 0, 10, 4, 0]])
# 由邻接矩阵创建NetworkX图
Graph = nx.from_numpy_array(adj_arr)
# 方式1: 采用kruskal算法求该图的最小生成树
min_span_tree = nx.minimum_spanning_tree(Graph, algorithm='kruskal')
# 方式2: 采用prim算法直接获取该图最小生成树的边
# data=False表示返回值不带权重
min_span_tree_edges = nx.minimum_spanning_edges(Graph, algorithm='prim', data=False)
# 绘图
plt.figure(figsize=(7, 5), dpi=100)
pos = nx.spring_layout(Graph)
nx.draw_networkx(Graph, pos)
node_labels = nx.get_node_attributes(Graph, 'node_name')
nx.draw_networkx_labels(Graph, pos, labels=node_labels)
edge_labels = nx.get_edge_attributes(Graph, 'weight')
nx.draw_networkx_edge_labels(Graph, pos, edge_labels=edge_labels)
plt.show()
# 打印结果
print('图的边及权重:\n', Graph.edges(data=True))
# 无向图,对结果无影响
print('最小生成树的边= ', sorted(min_span_tree.edges()))
print('最小生成树的边= ', sorted(min_span_tree_edges))
- 结果
2. Kruskal算法
Kruskal算法:闭圈法。开始选择一条最小权的边,以后迭代中,总从与已选边不构成圈的那些未选边中,选择一条权最小的。(每一步中,如果有两条或两条以上的边都是权最小的边,则从中任意选一条)
- 代码
import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
# 邻接矩阵,0表示不邻接
M = 1000 # 排除自身,如果不连通,则用一个极大值替代
adj_arr = np.array([[0, 7, M, M, M, 5],
[7, 0, 9, M, 3, M],
[M, 9, 0, 6, M, M],
[M, M, 6, 0, 8, 10],
[M, 3, M, 8, 0, 4],
[5, M, M, 10, 4, 0]])
node_num = len(adj_arr) # 节点的数量
edges_num = 0 # 边的数量
edges_list = []
for i in range(node_num):
for j in range(i+1, node_num):
if adj_arr[i,j] < M:
edges_num += 1
edges_list.append([i, j, adj_arr[i][j]])
edges_list.sort(key=lambda x: x[2]) # 按照权的大小排序
print(node_num, edges_num, edges_list)
group = [[i] for i in range(node_num)]
res = []
for edge in edges_list:
for i in range(len(group)):
if edge[0] in group[i]:
m = i
if edge[1] in group[i]:
n = i
if m != n:
res.append(tuple(edge[0:2]))
group[m] = group[m] + group[n]
group[n] = []
print('Kruskal=', sorted(res))
- 结果