📌  相关文章
📜  具有 N 个顶点的树的可能数量(1)

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

给定 N 个顶点,树的可能数量

在组合数学中,给定 $n$ 个不同的节点,有多少种可以构成树的方法?也就是说,有多少种不同的无向图是连通的,且不包含环的。

让我们看看一些小树来更好地理解这个问题:

  • 当 $n = 1$ 时,只有一个节点,只有一棵树。
  • 当 $n = 2$ 时,只有两个节点,只有一棵树。
  • 当 $n = 3$ 时,有三种树,如下图所示:

  • 当 $n = 4$ 时,有 3 种形状的树,共有 6 棵树:

  • 当 $n = 5$ 时,有三种形状的树,共有 30 棵树:

  • 当 $n = 6$ 时,有 6 种形状的树,共有 156 棵树:

可以发现,对于每个 $n$,都有一种不同数量的树。我们如何计算这个数量呢?

推导公式

让我们使用递推公式来求出树的数量。设 $C_n$ 是具有 $n$ 个不同的节点的树的数量。

我们可以把一个具有 $n$ 个节点的树看成两部分:根节点和根节点 的所有子树。

考虑如下情况:

如果在上面的树中移动根节点(黄色的节点),我们会得到 $n$ 种不同的树。这是因为任何节点都可以成为根节点。

接下来考虑根节点的所有子树。

如果根节点没有子树,那么 $C_n$ 只是单个节点,所以 $C_1=1$。

对于根节点具有子树,我们可以把子树分成若干组。因为没有环,每个组都是一个树,并且这个组是由其根节点与外部网络相连,而组内部可能存在其他点。

对于每组内的节点数量,我们又可以把其看出一个子问题。换句话说,我们可以通过将组内节点作为一个整体,来计算每一组的贡献。

例如,考虑以下树:

这颗树从根节点开始,它有两个子树。左边有一个节点,右边有两个。我们可以考虑左边的子树。它只有一个节点,所以贡献为 $C_1=1$。

现在考虑右边的子树。它有两个节点,贡献为 $C_2$。这两个子问题已经独立处理,我们将它们的乘积作为这组的贡献。

因此,我们可以使用以下递归公式计算 $C_n$:

$$ C_n = \sum_{i=1}^n C_{i-1}C_{n-i} $$

注意到这是一个卡特兰数。

代码实现

现在我们来给出一个 Python 实现。我们需要计算 $C_0$ 到 $C_n$,这可以通过 Python 的列表来实现。

def catalan(n):
    if n <= 1:
        return 1
    c = [0] * (n + 1)
    c[0] = 1
    for i in range(1, n + 1):
        for j in range(i):
            c[i] += c[j] * c[i - j - 1]
    return c[n]

这个函数计算 $C_n$ 的复杂度为 $O(n^2)$。

如果你不关心具体的解,可以使用通向公式,其复杂度为 $O(1)$:

$$ C_n = \binom{2n}{n} - \binom{2n}{n+1} = \frac{1}{n+1}\binom{2n}{n} $$

这个公式计算 $C_n$ 的时间复杂度为 $O(1)$。相反,额外的空间复杂度是 $O(n)$。

结论

无论哪种方法,卡特兰数都是已知的最快增长的计数序列,其增长速度大约为 $4^n$,其排名在 OEIS 序列 A000108 中的第一项。

现在你可以很容易地计算一个小树的数目。