Prufer 序列

定义与性质

\(\tt Prufer\) 序列用于建立起有标号无根树 / 有根树与序列的双射关系。

考虑对于一颗有标号无根树按如下方式生成一个长度为 \(n - 2\) 的序列(特别地,我们不考虑 \(n = 1\) 的情况):

  • 找到树中的叶子节点当中编号最小的节点,将其在树上连接的点写在序列末尾,递归该操作。

由此我们发现该序列存在如下两条性质:

  1. 节点 \(n\) 最终一定存在与树中并未被删除。

  2. 每个点的度数为在序列中出现的次数 \(+1\)。

下面我们将证明,对于任意的长度为 \(n - 2\) 的序列 \(A\),若满足 \(A_i \in [1, n]\) 那么该序列都恰好可以对应一颗有标号无根树。

考虑按照该序列逐步还原这棵树。

既然 \(\tt Prufer\) 序列的生成方式与叶子节点密切相关,于是我们可以考虑维护叶子节点构成的集合。

最开始,叶子节点为所有度数为 \(1\) 的节点,为了方便,随着当前时刻的推进,我们同时维护出在当前时刻所有点的度数。

此时我们找出当前叶子集合当中编号最小的节点,他在原树中必然连接当前序列的第一个元素,于是我们直接连接并将序列第一个元素的度数 \(-1\),将时刻往后推进一位。

由于上述操作的唯一性,我们就可以导出上述结论。

由上述的结论,下面我们证明该序列与 \(n\) 个点的有标号无根树构成双射:

首先我们证明如下两条性质:

  1. 不存在两个 \(\tt Prufer\) 序列对应同一棵树。

  2. 不存在两棵树对应同一个 \(\tt Prufer\) 序列。

反证法:若存在两棵树对应同一个 \(\tt Prufer\) 序列,那么有这个 \(\rm Prufer\) 序列将会对应这两颗树,矛盾。

类似地可以证明不存在两个 \(\tt Prufer\) 序列对应同一棵树。

此时我们假设所有树构成的集合为 \(A\),所有 \(\tt Prufer\) 序列构成的集合为 \(B\)。

由性质一可得 \(|A| \le |B|\) 由性质二可得 \(|A| \ge |B|\),则可得 \(|A| = |B|\) 由有性质一二,则原命题得证。

疑问

此时我们存在一个疑问:为什么 \(\tt Prufer\) 序列必须要长度为 \(n - 2\),而不可以是 \(n - 1\)。

原因是实际上若长度为 \(n - 1\),虽然能还原一颗树,但最后一个元素就代表了这颗树的根与我们要求无根树不符。

当然若需要钦定根,那么只需把最后一个元素改成这个根即可。

求解方式

有两个部分:对于树求解对应的 \(\tt Prufer\) 序列,对于 \(\tt Prufer\) 序列求解对应的树。

先考虑前者,由定义显然可以获得 \(\mathcal{O(n \log n)}\) 的做法,发现瓶颈在于维护叶子节点编号最小值。

此时我们审视问题,可以发现如下性质:

  1. 要维护的点权 \(\le n\)。

  2. 每个点只会进一次堆,出一次堆。

那么每次一个点删除后,如果其在树上连接的点的编号小于其那么之后一定会做为下一个删除的节点。

对于这种情况我们直接删除该节点并递归即可,直到其在树上连接的点的编号大于其停止,然后找到其后第一个要删的叶子节点重复上述操作。

由于性质 \(1\),找到第一个要删的叶子节点直接在值域上维护一个指针即可。

可以发现指针的移动量为 \(\mathcal{O(n)}\),并且由于性质 \(2\),递归部分总量为 \(\mathcal{O(n)}\),因此复杂度为 \(\mathcal{O(n)}\)。

对于后者,可以使用类似的方法求解。

应用

有标号无根树数量

这是一个经典结论,答案为 \(n ^ {n - 2}\),可以利用原树和 \(\tt Prufer\) 序列构成双射简单证明。

确定每个点度数的有标号无根树数量

由于最开始提到的 \(\tt Prufer\) 序列性质 \(2\),已知每个点的度数等价于直到其在 \(\tt Prufer\) 序列中的出现次数。

假设每个度数构成序列 \(d\),那么这个问题的答案显然为:

\[\dbinom{n - 2}{d_1 - 1 ~~~~ d_2 - 1 ~~~~ d_3 - 1 ~~~~ \cdots ~~~~ d_n - 1} \]

需要特判无解的情况。

有标号无向图构成连通图的方案

令有 \(k\) 个连通块,第 \(i\) 个连通块大小为 \(s_i\),令 \(n = \sum s_i\)。

由于图是有标号的,因此我们只关心每个连通块连出去多少边,至于连到联通块内任意一点都对应着不同的方案。

那么我们不妨枚举每个连通块连出去的度数序列 \(d\),那么答案为:

\[\begin{aligned} Ans &= \sum\limits_{d, \sum d_i = 2k - 2} \dbinom{k - 2}{d_1 - 1 ~~~~ d_2 - 1 ~~~~ d_3 - 1 ~~~~ \cdots ~~~~ d_k - 1} \prod\limits_{i = 1} ^ k (s_i) ^ {d_i} \\ &= (k - 2)![x ^ {2k - 2}] \prod\limits_{i = 1} ^ k \left(\sum\limits_{j = 1} ^ \infty \frac{(s_i) ^ j}{(j - 1)!} x ^ j \right) \\ &= (k - 2)![x ^ {2k - 2}] \prod\limits_{i = 1} ^ k s_i x\left(\sum\limits_j ^ \infty \frac{(s_i) ^ j}{j!} x ^ j \right) \\ &= (k - 2)![x ^ {2k - 2}] \prod\limits_{i = 1} ^ k s_i \times e ^ {(s_i + 1)x} \\ &= (k - 2)!\prod\limits_{i = 1} ^ k s_i \times [x ^ {2k - 2}]e ^ {\sum\limits_{i = 1} ^ k (s_i + 1)x} \\ &= (k - 2)!\prod\limits_{i = 1} ^ k s_i \times [x ^ {2k - 2}]e ^ {(n + k)x} \\ &= n ^ {k - 2} \prod\limits_{i = 1} ^ k s_i \end{aligned} \]

上一篇:今日头条 2018 AI Camp 6 月 2 日在线笔试编程题第二道——两数差的和


下一篇:prufer序列计数的一些结论