Prüfer 序列

由于本人过菜,故写文备忘。

参考资料:

https://www.luogu.com.cn/blog/TheLostWeak/solution-p2290

https://oi-wiki.org/graph/prufer

https://github.com/cp-algorithms/cp-algorithms/blob/master/src/graph/pruefer_code.md

Prüfer 

Prüfer 序列常用于组合计数问题上。

Prüfer 序列可以将一个带标号 n 个结点的树用 [1,n] 中的 n2 个整数表示。你也可以把它理解为完全图的生成树与数列之间的双射。

从树到序列

每次选择一个编号最小叶结点并删掉它,然后在序列中记录下它连接到的那个结点。重复 n2 次后就只剩下两个结点,算法结束。

线性构造法

用指针 p 指向编号最小的度数为 0 的节点。先删掉 p,获得 x,为度数被更新的节点。如果 x 的度数不变为 0,即没有产生新的度数为 0 的节点,那么将 p 自增,直到找到度数为 0 的节点,此时 p 指向的就是下一个要删掉的节点。如果 x 的度数变为 0,我们 check 一下 xp 的大小:

x<p,意味着 p 在自增环节扫过 x,但当时由于 x 的度数限制,没有被删掉,如今 x 应当被删掉了,我们删掉 x,继续检索 x 是否致使产生新的 0 度节点,若产生了,并且产生的节点编号 <p,循环执行删除,如果否,退出循环。
注意在这个过程中不改动 p,因为 p 可以在上述操作后仍保持原有 1 到 p-1 间不存在 0 度节点的性质。

x>p,意味着虽然 x 的度数变成 0 了,但是 p 并未在自增环节扫过 x,也就是说 x 的编号顺序不一定满足条件。反正之后会扫到 x,我们当前直接跳过。

循环执行直到未被删除的节点只剩 2 个,结束。

//此代码摘取自https://github.com/cp-algorithms/cp-algorithms/blob/master/src/graph/pruefer_code.md
vector<int> code(n - 2);
int leaf = ptr;
for (int i = 0; i < n - 2; i++) {
int next = parent[leaf];
code[i] = next;
if (--degree[next] == 1 && next < ptr) {
leaf = next;
} else {
ptr++;
while (degree[ptr] != 1) ptr++;
leaf = ptr;
}
}

复杂度分析:除了删除节点和 p 自增的均摊 O(n) 之外其余操作均 O(1)。总复杂度 O(n)

从序列到树

刚开始你有一个点集 V={v|1vn},这个点集是所有没连边的节点的集合。

循环执行以下操作:

拿出 Prüfer 序列最靠前的数,拿出点集中不在当前 Prüfer 序列中的编号最小的点。在两个点之间连一条边。

同样可以线性时间解决。

性质

  1. Prüfer 序列与无根树为双射关系。
  2. 度数为 di 的节点会在序列中出现 di1 次。
  3. 节点 n 一定会活到最后。

例题

P2290 [HNOI2004] 树的计数

给定了每个节点的度数,那么该节点在 Prüfer 序列中出现次数也确定了。那么就是一个可重集合排列。

P4981 父子

n 个节点无根树的个数根据 Cayley 公式得到,由于节点之间互异,不同节点当根不会产生同构,所以有根树个数 ×n 即可。

Cayley (Cayleys formula)

n 个节点可以产生 nn2 种连通无根树。

用 Prüfer 序列证明:任意一个长度为 n2 的值域 [1,n] 的整数序列都可以通过 Prüfer 序列映射为一个生成树,故种类为 nn2

以下内容 copy 自 OIwiki。本人还没阅读。

Prüfer 序列可能比你想得还强大。它能创造比凯莱公式更通用的公式。比如以下问题:

一个 [n] 个点 [m] 条边的带标号无向图有 [k] 个连通块。我们希望添加 [k-1] 条边使得整个图连通。求方案数。

证明

si 表示每个连通块的数量。我们对 k 个连通块构造 Prüfer 序列,然后你发现这并不是普通的 Prüfer 序列。因为每个连通块的连接方法很多。不能直接淦就设啊。于是设 di 为第 i 个连通块的度数。由于度数之和是边数的两倍,于是
i=1kdi=2k2 。则对于给定的 d 序列构造 Prüfer 序列的方案数是

(k2d11,d21,,dk1)=(k2)!(d11)!(d21)!(dk1)!

对于第 i 个连通块,它的连接方式有 sidi 种,因此对于给定 d 序列使图连通的方案数是

(k2d11,d21,,dk1)i=1ksidi

现在我们要枚举 d 序列,式子变成

di1i=1kdi=2k2(k2d11,d21,,dk1)i=1ksidi

好的这是一个非常不喜闻乐见的式子。但是别慌!我们有多元二项式定理:

(x1++xm)p=ci0, i=1mci=p(pc1,c2,,cm)i=1mxici

那么我们对原式做一下换元,设 ei=di1 ,显然
i=1kei=k2 ,于是原式变成

ei0i=1kei=k2(k2e1,e2,,ek)i=1ksiei+1

化简得到

(s1+s2++sk)k2i=1ksi

nk2i=1ksi

这就是答案啦

posted @   xcr0987  阅读(58)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示