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} ]

    证毕!

    珍爱生命,远离抄袭!
  • 相关阅读:
    XML错误信息Referenced file contains errors (http://www.springframework.org/schema/beans/spring-beans-4.0.xsd). For more information, right click on the message in the Problems View ...
    Description Resource Path Location Type Cannot change version of project facet Dynamic Web Module to 2.3.
    maven创建web报错Cannot read lifecycle mapping metadata for artifact org.apache.maven.plugins:maven-compiler-plugin:maven-compiler-plugin:3.5.1:runtime Cause: error in opening zip file
    AJAX跨域
    JavaWeb学习总结(转载)
    JDBC学习笔记
    Java动态代理之JDK实现和CGlib实现
    (转)看懂UML类图
    spring boot配置使用fastjson
    python3下django连接mysql数据库
  • 原文地址:https://www.cnblogs.com/ycx-akioi/p/prufer.html
Copyright © 2011-2022 走看看