Prufer 序列小记

(prufer 序列仅对 (n>1) 有效,(n=1) 一般要特判)

prufer 序列是 (n) 个点的有标号无根树集合与 (([1,n]cap)^{n-2}) 的一种双射方式,可以将不会处理的树形结构转化为数组,在很多计数题里很有用。

下面先给出 prufer 序列的构造方式(即定义),然后给出通过任意长度为 (n-2) 每个元素 (in[1,n]) 的序列作为 prufer 序列还原出存在唯一的树的方式(也就自然证明了双射性)。

从树构造 prufer 序列

一次操作指找到当前编号最小的叶子,将它唯一连向的点的编号 append 进 prufer 序列,并且删除该叶子。进行 (n-2) 次操作,还剩下两个由一条边相连的点,此时得到的长度为 (n-2) 的序列则为 prufer 序列。

注意到 (n) 永远不会成为被找到的叶子,所以可以钦定 (n) 为根,那么每次叶子唯一连向的点就是父亲,这样使实现更方便。考虑实时维护各节点的儿子个数,等于 (0) 则及时加入叶子集合,每次从叶子集合里找最小的,可以用堆简单地线对维护。

事实上有线性做法。注意到每次插入后必找最小值,那就可以看刚刚插入的是否最小值,如果是的话就直接用掉,否则才加入叶子集合。这样一来叶子集合的最小值是有单调性的,可以直接用桶存,然后对最小值「one-pointer」即可。

code:

void prf_init(){
	for(int i=1;i<n;i++)deg[fa[i]]++;
	for(int i=1;i<=n;i++)if(!deg[i])hav[i]++;
	int now=1,least=0,d;
	for(int i=1;i<=n-2;i++){
		if(least)d=least,least=0;
		else{while(!hav[now])now++;d=now;hav[now]--;}
		prf[i]=fa[d];
		if(!--deg[fa[d]])if(fa[d]<now)least=fa[d];else hav[fa[d]]++;
	}
}

从 prufer 序列还原树

通过 prufer 序列的定义易知 (i) 在 prufer 序列中出现的次数就等于 (deg_i-1)(对 (x eq n)(x) 的儿子全被删除了;对 (x=n)(x) 恰有一个儿子没被删除,但相比非根节点没有父亲对度数的贡献)。那么通过 prufer 序列就可以知道每个点的儿子个数,一开始也就能知道叶子集合。

考虑从左往右通过已知的叶子集合模拟 prufer 序列的构造过程。每次找到最小叶子、删除,可知当前最小叶子跟当前 prufer 值有一条边。如此 (n-2) 次之后连了 (n-2) 条边,还剩一条边是剩下两个点的边,其中一个是 (n),另一个就在 ([1,n)) 里找一下谁还没爸爸。

通过叶子集合模拟的过程就跟上面构造 prufer 序列的线性做法一模一样地做即可。所以说构造和还原的代码其实基本一样。

code:

void fa_init(){
	for(int i=1;i<=n-2;i++)deg[prf[i]]++;
	for(int i=1;i<=n;i++)if(!deg[i])hav[i]++;
	int now=1,least=0,d;
	for(int i=1;i<=n-2;i++){
		if(least)d=least,least=0;
		else{while(!hav[now])now++;d=now;hav[now]--;}
		fa[d]=prf[i];
		if(!--deg[fa[d]])if(fa[d]<now)least=fa[d];else hav[fa[d]]++;
	}
	for(int i=1;i<n;i++)if(!fa[i])fa[i]=n;
}

mol ban tea & code

由此可得一个小结论(当然 prufer 序列的应用远不止于此):(n>1) 个点的有标号无根树数量为 (n^{n-2})。其实用矩阵树定理也能证(只不过稍烦),就胡个证明吧(就当练习一下线代吧)。

其实就是无向图生成树个数,造出基尔霍夫矩阵,只要证 (n-1) 阶行列式

[egin{vmatrix}n-1&-1&-1&cdots&-1\-1&n-1&-1&cdots&-1\-1&-1&n-1&cdots&-1\vdots&vdots&vdots&ddots&-1\-1&-1&-1&-1&n-1end{vmatrix}=n^{n-2} ]

将第一行作为减数减到其他所有行上,设 (x) 阶方阵 (K_x)

[egin{bmatrix}n-1&-1&-1&cdots&-1\-n&n\-n&&n\vdots&&&ddots\-n&&&&nend{bmatrix} ]

只要证 (|K_{n-1}|=n^{n-2})。事实上我们有 (|K_x|=(n-x)n^{x-1})(这是证明不是推导/xyx),下面按 (x) 归纳证明之。

(|K_1|=n-1) 显然满足。当 (x>1) 时,将 (K_x) 按第二行展开:((2,1)) 余子式是个上三角矩阵,显然等于 (-n^{x-2})((2,2)) 余子式显然是 (|K_{x-1}|);其他位置都是 (0),无贡献。假设 (K_{x-1}) 满足,有

[egin{aligned}|K_x|&=(-1)^{2+1}(-n)!left(-n^{x-2} ight)+(-1)^{2+2}n(n-x+1)n^{x-2}\&=-n^{x-1}+(n-x+1)n^{x-1}\&=(n-x)n^{x-1}end{aligned} ]

证毕!

珍爱生命,远离抄袭!
原文地址:https://www.cnblogs.com/ycx-akioi/p/prufer.html