📜  生成树 gfg 的数量 (1)

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

生成树 GFG 的数量

在图论中,生成树指的是一棵包含所有节点的树。给定一个连通图,生成树可以通过去掉一些边来得到。生成树的数量在许多应用中都很重要。

算法1: Cayley公式

Cayley公式是计算生成树数量的一种经典方法。它规定,n个节点的完全图所构成的生成树的数量为n^(n-2)

from math import pow

def count_spanning_trees(n: int) -> int:
    return int(pow(n, n-2))
算法2: Matrix-Tree定理

Matrix-Tree 定理是计算生成树数量的另一种方法。它要求使用一个有向加权图的邻接矩阵来计算。邻接矩阵中的元素aij表示从节点i到节点j的有向边的权重。定义D(i, i)为i节点的度数,也就是邻接矩阵第i行的所有元素之和。则,n个节点的有向加权图的生成树数量为:

    T = 1/(n-1) * det(L)

其中,L为邻接矩阵去掉任意一行一列后得到的子矩阵。

import numpy as np

def count_spanning_trees(adj_matrix: np.ndarray) -> int:
    n, m = adj_matrix.shape
    assert n == m and n >= 2, "Invalid Adjacency matrix"
    D = np.zeros(n)
    for i in range(n):
        D[i] = np.sum(adj_matrix[i,:])
    L = adj_matrix - np.diag(D)
    Lsub = L[1:,1:]
    T = np.linalg.det(Lsub)
    T = int(T * (n-1))
    return T
算法3: Prufer序列

Prufer序列的生成树计数方法非常高效,适用于非常大的图。该方法的思想是,对于n个顶点的树,任何时候都存在一种顶点数为n-2的子树,生成树的过程是在这个子树上添加一个新的顶点,并选择一个合适的边连接到子树上。因此,我们可以通过移除叶子节点并记录将其连接到子树中的边来构建Prufer序列。

def get_prufer(seq: List[int]) -> int:
    n = len(seq) + 2
    deg = [1] * n
    leaf = []
    for v in seq:
        deg[v] += 1
    for i in range(1, n):
        if deg[i] == 1:
            leaf.append(i)
    for v in seq:
        w = leaf.pop(0)
        deg[v] -= 1
        if deg[v] == 1:
            leaf.append(v)
        # Output edge (v, w)
    x, y = leaf
    # Output edge (x, y)
    
def count_spanning_trees(n: int) -> int:
    ans = 1
    for i in range(n-2):
        ans *= n
        n -= 1
    return ans

注意,第3个算法也是通过计算任意连通图的生成树数来得到,因此需要计算生成树数量的时候,可以将其当做通用方法来使用。