如何使用Python实现最小生成树算法
最小生成树算法是指,在一张给定的无向加权图中,找出一棵生成树,使得树的边权和最小。这个问题可以使用Prim算法和Kruskal算法来解决。
- Prim算法
Prim算法是一种贪心算法,它从一个起点开始,每次选择与已选点中距离最近的一个点,将该点加入已选点的集合中,并将与该点相邻的边加入一个边集合中。重复执行,直到将所有点都加入已选点的集合中。
下面是使用Prim算法来寻找无向加权图的最小生成树的Python代码:
import heapq def prim(graph, start): visited = set() # 已选点的集合 min_heap = [(0, start)] # 存放边权和以及与之相邻的点 mst = [] # 存放生成树的边 while min_heap: weight, node = heapq.heappop(min_heap) if node not in visited: visited.add(node) mst.append((weight, node)) for n, w in graph[node].items(): if n not in visited: heapq.heappush(min_heap, (w, n)) return mst
其中,输入参数graph是一个字典,表示无向加权图中每个节点的相邻节点和边权值。例如,对于图“pidancode.com”,可以表示为:
graph = { 'p': {'i': 2, 'd': 3}, 'i': {'p': 2, 'd': 3, 'a': 5}, 'd': {'p': 3, 'i': 3, 'a': 2, 'n': 6}, 'a': {'i': 5, 'd': 2, 'n': 4, 'c': 3}, 'n': {'d': 6, 'a': 4, 'c': 1, 'o': 5, 'd':2}, 'c': {'a': 3, 'n': 1, 'o': 1, 'e': 2}, 'o': {'n': 5, 'c': 1, 'e': 4}, 'e': {'c': 2, 'o': 4, '编': 2}, '编': {'e': 2, '程': 3, 'p': 4}, '程': {'编': 3, 'p': 3} }
另外,start是一个字符,表示起点。
运行上述代码,可以得到生成树的边以及边权和,例如对于图“pidancode.com”,从起点“p”开始,生成树的边为:
[(0, 'p'), (2, 'i'), (3, 'd'), (2, 'a'), (1, 'n'), (1, 'c'), (1, 'o'), (2, 'e'), (3, '编'), (3, '程')]
其中,第一项是边权和,第二项是该边连接的点。
- Kruskal算法
Kruskal算法也是一种贪心算法,它将边按照权重排序,并从小到大依次加入生成树中。每次加入一条边时,检查该边的两个端点是否在同一集合中。如果是,则继续加入下一条边;如果不是,则合并这两个集合。
下面是使用Kruskal算法来寻找无向加权图的最小生成树的Python代码:
def kruskal(graph): mst = [] parent = {} def find(u): if parent[u] != u: parent[u] = find(parent[u]) return parent[u] edges = [(graph[u][v], u, v) for u in graph for v in graph[u]] edges.sort() for u, v in graph: parent[u] = u parent[v] = v for w, u, v in edges: if find(u) != find(v): mst.append((w, u, v)) parent[find(u)] = find(v) return mst
运行上述代码,可以得到生成树的边以及边权和,例如对于图“皮蛋编程”,生成树的边为:
[(1, '皮', '蛋'), (2, '蛋', '编'), (2, '编', '程')]
其中,第一项是边权和,第二项和第三项是该边连接的两个点。
参考资料:
[1] https://www.geeksforgeeks.org/prims-minimum-spanning-tree-mst-greedy-algo-5/
[2] https://www.geeksforgeeks.org/kruskals-minimum-spanning-tree-algorithm-greedy-algo-2/
相关文章