📜  离散数学-生成树(1)

📅  最后修改于: 2023-12-03 15:41:03.990000             🧑  作者: Mango

生成树

在计算机科学中,生成树是一种树形数据结构,由图中的所有节点组成,形成一棵无环子图。生成树在离散数学中有广泛的应用,其中包括连通性、网络流、最短路径等领域。

最小生成树

最小生成树是一种生成树,其边的权值之和最小。最小生成树算法包括普林姆算法和克鲁斯卡尔算法。

普林姆算法

普林姆算法使用一个辅助数组 key[] 来保存每个节点与当前生成树的边中最小权值。初始化数组 key[] 的值为无穷大。将第一个节点加入生成树,然后根据 key[] 来选择下一个节点加入生成树。依次类推,直到生成整个树。

普林姆算法的时间复杂度为 O(V²),其中 V 是节点数量。

以下是普林姆算法的 Python 代码实现:

def prim(graph):
    n = len(graph)
    visited = [False] * n
    key = [float('inf')] * n
    parent = [-1] * n
    key[0] = 0
    for _ in range(n):
        u = key.index(min(key))
        visited[u] = True
        for v in range(n):
            if graph[u][v] and not visited[v] and graph[u][v] < key[v]:
                key[v] = graph[u][v]
                parent[v] = u
    return parent
克鲁斯卡尔算法

克鲁斯卡尔算法是一种基于贪心思想的最小生成树算法。它的基本思路是将所有边按权值从小到大排序,然后依次选取边加入生成树,保证不形成环。直到生成整个树。

克鲁斯卡尔算法的时间复杂度为 O(E log E),其中 E 是边数量。

以下是克鲁斯卡尔算法的 Python 代码实现:

class Subset:
    def __init__(self, parent, rank):
        self.parent = parent
        self.rank = rank

def find(subsets, i):
    if subsets[i].parent != i:
        subsets[i].parent = find(subsets, subsets[i].parent)
    return subsets[i].parent

def union(subsets, x, y):
    x_root = find(subsets, x)
    y_root = find(subsets, y) 
    if subsets[x_root].rank < subsets[y_root].rank:
        subsets[x_root].parent = y_root
    elif subsets[x_root].rank > subsets[y_root].rank:
        subsets[y_root].parent = x_root
    else:
        subsets[y_root].parent = x_root
        subsets[x_root].rank += 1

def kruskal(graph):
    result = []
    i, e = 0, 0 
    n = len(graph)
    graph_sorted = sorted([(graph[i][j], i, j) for i in range(n) for j in range(i+1, n) if graph[i][j]], key=lambda x: x[0])
    subsets = [Subset(i, 0) for i in range(n)]
    while e < n - 1:
        w, u, v = graph_sorted[i]
        i += 1
        x = find(subsets, u)
        y = find(subsets, v)
        if x != y:
            e += 1
            result.append((u, v))
            union(subsets, x, y)     
    return result