如何使用Python实现最小生成树算法

2023-04-17 00:00:00 算法 如何使用 最小

最小生成树算法是指,在一张给定的无向加权图中,找出一棵生成树,使得树的边权和最小。这个问题可以使用Prim算法和Kruskal算法来解决。

  1. 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, '程')]

其中,第一项是边权和,第二项是该边连接的点。

  1. 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/

相关文章