zoukankan      html  css  js  c++  java
  • 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} ]

    证毕!

    珍爱生命,远离抄袭!
  • 相关阅读:
    JAVA 笔记二  转
    JAVA 笔记一  转
    在Eclipse中设置中文JavaDOC
    java session用法
    使用Session防止表单重复提交
    君の瞳に乾杯
    今夜では一人で雛祭り 03
    今夜では一人で雛祭り 02
    今夜では一人で雛祭り    001
    十年目のバレンタインデー   002
  • 原文地址:https://www.cnblogs.com/ycx-akioi/p/prufer.html
Copyright © 2011-2022 走看看