CloudySky

纵使世界万般残酷

总有温暖值得守护

Prufer 序列 学习笔记

注:这是一个散片笔记,内容较少。

PruferPrufer 序列是一种可以方便的进行图上计数的序列。最早被拿来证明凯莱定理。

PruferPrufer 序列必须在无根树上构造,构造方法:

  • 每次选择一个编号最小的叶子节点,将它从树上删除,同时将与它相连的点(由于是无根树,所以这样表示,也就是它的父亲)加入序列。

  • 重复这一过程直到序列长度为 n2n - 2

简单性质:

  • 一个点在 PruferPrufer 序列中出现的次数等价于它的度数 1-1

  • 最后剩下的 22 个点中,必然包括 nn 号节点。

  • 每个无根树与它的 PruferPrufer 序列成双射关系。

    所以这个东西也可以被用来对拍,因为 PruferPrufer 序列一定合法且可以对应一棵树。

PruferPrufer 序列的线性构造

用上面的定义进行构造,用堆维护最小值显然是可以的,但复杂度不够优。

因为 PruferPrufer 序列是按照特殊的权值编号来构造的,所以就会有的特殊性质。

具体实现:

  1. 顺序遍历数组,找到叶子节点 yy

  2. 找到之后将它的父亲加进 PruferPrufer 序列,将父亲节点度数 1-1 。如果父亲节点变成了叶子节点,设父亲的父亲的编号为 xx ,按照 xxyy 的大小关系进行分类讨论:

    1. x>yx > y 之后一定会扫到 xx ,所以不用进行任何操作。

    并且也不能进行任何操作,因为 [x+1,y1][x + 1, y - 1] 可能有叶子节点 zz,这时候显然是先要处理 zz ,再处理 yy 的。

    1. x<yx < y 这个时候需要直接xx 设为 yy 并直接重复进行 2.22.2 (如果满足条件的话)。

      注:为了保证复杂度,不能直接将 yy 改变,而是应该采用别的方法,如利用 py=xp_y = x 不断地利用 pp 数组进行更新。

这样整个算法下来,每个点只会被删除一次,并且已经被删除的点不会被重复扫到,所以时间复杂度是线性的。

代码实现:
1
2
3
4
5
6
7
8
9
10
11
12
// Prufer 序列 学习笔记
// Prufer 序列的线性构造
void build (int n) {
memset (p, 0, sizeof (p));
for (int i = 1, j = 1; i <= n - 2; ++i, ++j) {
while (d[j]) ++j;
p[i] = f[j];
// 一定要先修改 d[] 再进行编号判断
while (i <= n - 2 && --d[p[i]] == 0 && p[i] < j)
p[i + 1] = f[p[i]], ++i;
}
}

PruferPrufer 重构树与线性实现

因为 PruferPrufer 序列与树双射,所以可以将它映射回树。

首先要把 p[n1]p[n - 1] 赋成 nn ,因为考虑正着求 PruferPrufer 序列第 n1n - 1 项一定是 nn ,只是因为它没有用所以跳过了而已。

然后直接跑一边,把所有赋值语句都左右交换。

代码实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
// Prufer 序列 学习笔记
// Prufer 重构树与线性实现
void rebuild (int n) {
memset (f, 0, sizeof (f));
p[n - 1] = n;
for (int i = 1, j = 1; i <= n - 1; ++i, ++j) {
while (d[j]) ++j;
f[j] = p[i];
// 一定要先修改 d[] 再进行编号判断
while (i <= n - 1 && --d[p[i]] <= 0 && p[i] < j)
f[p[i]] = p[i + 1], ++i;
}
}

性质:

  • 首先是用来被证明的凯莱公式:完全图 KnKnnn2n^{n - 2} 个生成树。

    一个 pruferprufer 对应一棵树,长度为 n2n - 2 值域为 [1,n][1, n] 因此有 nn2n^{n - 2} 个生成树。

  • 一个 nn 个点 mm 条边的无向图,有 kk 个连通块,想通过 k1k - 1 条边将他连成连通图。设每个连通块的大小为 sis_i ,方案数为 nk2i=1ksin^{k - 2}\cdot \prod_{i = 1}^k s_i

    首先,感性理解是很好理解的,每个连通块向外连边的方案数为点数,内部联通情况为 nk2n^{k - 2} ,证明:

    did_i 表示第 ii 个连通块的度数。很容易发现:

    i=1kdi=2k2\sum_{i = 1}^k d_i = 2k - 2

    那么方案数为

    i=1kdi(k2d11,d21,,dk1)i=1ksidi化简为2k2(k2d11,d21,,dk1)i=1ksidi换元,设ei=di1,k2(k2e1,e2,,ek)i=1ksiei+1带入二项式定理(s1+s2++sk)k2i1ksink2i=1ksi\sum_{\sum_{i = 1}^k d_i}\binom{k - 2}{d_1 - 1, d_2 - 1, \cdots, d_k - 1}\cdot\prod_{i = 1}^k s_i^{d_i} \\ \text{化简为} \sum_{2k - 2}\binom{k - 2}{d_1 - 1, d_2 - 1, \cdots, d_k - 1}\cdot\prod_{i = 1}^k s_i^{d_i} \\ \text{换元,设} e_i = d_i - 1, \\ \sum_{k - 2}\binom{k - 2}{e_1, e_2, \cdots, e_k}\cdot\prod_{i = 1}^ks_i^{e_i + 1} \\ \text{带入二项式定理} (s_1 + s_2 + \cdots + s_k)^{k - 2}\cdot\prod_{i - 1}^ks_i \\ n^{k - 2}\cdot\prod_{i = 1}^ks_i

本文作者:CloudySky
写作时间: 2022-01-18
最后更新时间: 2022-01-18
遵循协议: BY-NC-SA

Top