【学习笔记】树的计数,prufer(Prüfer)编码,Cayley公式及相应例题
目录
- 1、pruferpruferprufer编码
- 1)无根树转化为prufer序列
- 2)prufer序列转化为无根树。
- 2、Cayley公式
- 1)由Cayley公式得到四个推论
- 例题1、P4981 父子
- 例二、P4430 小猴打架
具体的内容见:https://www.luogu.com.cn/blog/TheLostWeak/solution-p2290
我花了半个小时写完了以后后忘记保存直接关掉了,然后就没有然后了…已经不想更新了…
1、pruferpruferprufer编码
首先引入pruferpruferprufer编码(其实是Pru¨ferPrüferPru¨fer)
pruferpruferprufer数列,可以用来解一些关于无根树计数的问题。
pruferpruferprufer数列是一种无根树的编码表示,对于一 棵 nnn 个节点带编号的无根树,对应唯一一串长度为n-1的pruferpruferprufer编码。
1)无根树转化为prufer序列
一棵无根树的pruferpruferprufer编码的值运算如下:
首先定义无根树中度数为1的节点是叶子节点。 找到编号最小的叶子并删除,序列中添加与之相连的节点编号,重复执行直到只剩下2个节点。
如图:
它的pruferpruferprufer编码就是4, 3, 3
先丢1,4加入序列,再丢2,3加入序列,再丢5,3加入序列,剩余两个,停止丢人,序列为4,3,3
显然,一棵有n个结点的无根树,它的 pruferpruferprufer 编码是唯一的,且有 n−2n-2n−2 个可能相同的元素。
具体实现可以用一个setsetset搞定,维护度数为 111 的节点。复杂度O(nlogn)O(nlogn)O(nlogn)。
2)prufer序列转化为无根树。
设点集V=(1,2,3,...,n)V=(1,2,3,...,n)V=(1,2,3,...,n),每次取出prufer序列中最前面的元素u,在V中找到编号最小的没有在pruferpruferprufer序列中出现的元素v,给u,v连边然后分别删除,最后在V中剩下两个节点,给它们连边。最终得到的就是无根树。
具体实现也可以用一个setsetset,维护pruferpruferprufer序列中没有出现的编号。复杂度O(nlogn)O(nlogn)O(nlogn)。
很显然,每一个prufer序列与一棵无根树一一对应。
因此,对于一棵已知有n个结点的无根树,一定有一个n-2长度的序列,那么,我们枚举所有长度为n-2的序列,发现其与所有可能形态的无根树一一对应。而这种序列,根据乘法原理,有**n n-2**个可能的序列。
因此,对于一个已知的n,有n n-2 种不同的无根树。
最后有一个很重要的性质就是 pruferpruferprufer 序列中某个编号出现的次数就等于这个编号的节点在无根树中的度数-1。
(例如最上面的图中4,3,3,4的度数为2,3的度数为3。)
2、Cayley公式
Cayley公式是说,一个无向完全图有 nn−2n^{n-2}nn−2 棵生成树,通俗的说就是n个节点的带编号的无根树有 nn−2n^{n-2}nn−2个。
刚才Prufer有一个很重要的性质:序列与树是一一对应的
而Prufer序列有n-2项,序列中的每个数都在1到n的范围内。
所以我们可以直接推出n个点的无向完全图的生成树的计数:nn−2n^{n-2}nn−2
一个有趣的推广是,n个节点的度依次为D1, D2, …, Dn的无根树共有 (n−2)!/[(D1−1)!(D2−1)!..(Dn−1)!](n-2)! / [ (D1-1)!(D2-1)!..(Dn-1)! ](n−2)!/[(D1−1)!(D2−1)!..(Dn−1)!] 个,因为此时Pru¨ferPrüferPru¨fer编码中的数字i恰好出现Di−1Di-1Di−1次(上面的结论)。
1)由Cayley公式得到四个推论
一棵n个节点的无根树唯一地对应了一个长度为n-2的数列,数列中的每个数都在1到n的范围内。
上面这句话比较重要。通过上面的定理,
1) 我们可以直接推出n个点的无向完全图的生成树的计数:n(n-2) 即n个点的有标号无根树的计数。
2) 一个有趣的推广是,n个节点的度依次为D1,D2,…,DnD1, D2, …, DnD1,D2,…,Dn的无根树共有 (n−2)!/[(D1−1)!(D2−1)!..(Dn−1)!](n-2)! / [ (D1-1)!(D2-1)!..(Dn-1)! ](n−2)!/[(D1−1)!(D2−1)!..(Dn−1)!] 个,因为此时Pru¨ferPrüferPru¨fer编码中的数字i恰好出现Di-1次。
即 n种元素,共n−2n-2n−2个,其中第 iii 种元素有Di−1Di-1Di−1个,求排列数。
3) n个节点的度依次为D1,D2,…,DnD1, D2, …, DnD1,D2,…,Dn,令有m个节点度数未知,求有多少种生成树?(BZOJ1005 明明的烦恼)
令每个已知度数的节点的度数为di,有n个节点,m个节点未知度数,left=(n−2)−(d1−1)−(d2−1)−...−(dk−1)left=(n-2)-(d1-1)-(d2-1)-...-(dk-1)left=(n−2)−(d1−1)−(d2−1)−...−(dk−1)
已知度数的节点可能的组合方式如下
(n−2)!/(d1−1)!/(d2−1)!/.../(dk−1)!/left!(n-2)!/(d1-1)!/(d2-1)!/.../(dk-1)!/left!(n−2)!/(d1−1)!/(d2−1)!/.../(dk−1)!/left!
剩余left个位置由未知度数的节点随意填补,方案数为mleft
于是最后有
ans=(n−2)!/(d1−1)!/(d2−1)!/.../(dk−1)!/left!∗mleftans=(n-2)!/(d1-1)!/(d2-1)!/.../(dk-1)!/left! * m^leftans=(n−2)!/(d1−1)!/(d2−1)!/.../(dk−1)!/left!∗mleft
例题1、P4981 父子
P4981 父子
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#define ls (p<<1)
#define rs (p<<1|1)
#define mid (l+r)/2
#define over(i,s,t) for(register int i=s;i<=t;++i)
#define lver(i,t,s) for(register int i=t;i>=s;--i)
using namespace std;
typedef long long ll;//全用ll可能会MLE,ll比int占的内存大
const ll N=1002;
const ll INF=1e9+9;
const ll mod=1e9+9;
const double EPS=1e-6;
ll n,m;
inline ll qpow(ll a,ll b)
{ll res=1;while(b){if(b&1)res=(res*a)%mod;a=(a*a)%mod;b>>=1;}return res;
}
int main()
{ll t;scanf("%lld",&t);while(t--){scanf("%lld",&n);printf("%lld\n",qpow(n,n-1));}return 0;
}
例二、P4430 小猴打架
P4430 小猴打架
由 CayleyCayleyCayley定理,n个节点的带标号的形态不同的无根树有nn−2n^{n-2}nn−2n 个,这个purferpurferpurfer序对应的树有(n−1)(n-1)(n−1)条边, 如果还要考虑这棵树的生成顺序的话, 那就是n−1n-1n−1条边全排列:(n−1)!(n-1)!(n−1)!
答案(n−1)!∗nn−2mod9999991(n-1)!*n^{n-2} mod 9999991(n−1)!∗nn−2mod9999991
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#define ls (p<<1)
#define rs (p<<1|1)
#define mid (l+r)/2
#define over(i,s,t) for(register int i=s;i<=t;++i)
#define lver(i,t,s) for(register int i=t;i>=s;--i)
using namespace std;
typedef long long ll;//全用ll可能会MLE,ll比int占的内存大
const ll N=1002;
const ll INF=1e9+9;
const ll mod=9999991;
const double EPS=1e-6;
int main()
{ll n,ans=1;scanf("%lld",&n);over(i,1,n-2)ans=(ans*n)%mod;over(i,1,n-1)ans=(ans*i)%mod;printf("%lld\n",ans);return 0;
}
注:如果您通过本文,有(qi)用(guai)的知识增加了,请您点个赞再离开,如果不嫌弃的话,点个关注再走吧 ! 当然,也欢迎在讨论区指出此文的不足处,作者会及时对文章加以修正 !
【学习笔记】树的计数,prufer(Prüfer)编码,Cayley公式及相应例题相关推荐
- haxe php,Haxe学习笔记(一) Haxe:一次编码全平台编译的神话
Haxe学习笔记(一) Haxe:一次编码全平台编译的神话 一 Haxe是什么? Haxe是开源的,它作为一门语言,基础语法和ActionScript3基本一致.所以任何做过Flash开发的人都可以很 ...
- 学习笔记(一)(x264编码流程)
学习笔记(一)(x264编码流程) 作者 张士辉 11月 2, 2007 <script type=text/javascript></script> <script s ...
- 解题报告(八) prufer 序列与 Cayley 公式(ACM / OI)超高质量题解
繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...
- bzoj1211 [HNOI2004]树的计数 prufer序列+组合数
如果独自去想出prufer序列实在太难了 所以就只能直接用结论,把树转成prufer序列后这棵树和prufer序列是一一对应的关系 树->prufer序列:每次找到所有叶子结点中编号最小的,删掉 ...
- 数据结构与算法学习笔记-树和二叉树
声明:本博客仅为本人学习途中做的笔记 采自青岛大学王卓老师的视频教学 主要内容为算法思路,具体代码实现还需修改后才能运行,望各位看官多多包涵,您的点赞与评论是对我最大的肯定! 1.树和二叉树的定义 数 ...
- NLP学习笔记6--Lecture/语言模型/预处理/独热编码/word2vec/文本特征工程
语言模型用来判断:是否一句话从语法上通顺 先分词 然后算出联合概率 怎么算? chain rule 条件很长的时候 会遇到一个问题 sparsity 数据的稀疏性 用马尔科夫假设 最简单的假设 之 ...
- 深度学习笔记(十二)---One-hot编码
在学习语义分割过程中,最后的逐像素分类网络中,对像素进行分类时使用了one-hot编码,这也是现分类任务中常用的一种分类方式.那么什么是one-hot编码呢?为什么使用One-hot呢? One-ho ...
- [学习笔记]树链剖分
基本思想 树链剖分一种对树进行划分的算法,它先通过轻重边剖分将树分为多条链,保证每条边属于且只属于一条链,然后再通过数据结构来维护每一条链. 一些定义 树链:树上的路径. 剖分:把路径分类为重链和轻链 ...
- Python数据结构学习笔记——树和图
目录 一.树的概念 二.二叉树的实现 (一)列表的列表 (二)结点与引用 三.图的概念 四.图的实现 (一)邻接矩阵 (二)邻接表 一.树的概念 树是一种数据结构,树由结点及连接结点的边组成,每个树有 ...
最新文章
- 计算机技能需求新排名:Python 仅排第 3,第 1 你可能猜不到哦
- WPF TabControl Unload俩次的解决方案
- php 数组Array 删除指定键名值
- case函数,replace函数
- Java操作Excel中HSSFCell.CELL_TYPE_STRING、BOOLEAN、NUMERIC无定义解决方法
- Javascript UserAgent 获取平台及浏览器信息
- Linux io运行情况,Linux IO调度层分析
- Oracle读取log日志,使用log miner 分析oracle日志
- Screens的开发一
- JSP+JSTL+EL表达式,实现web页面的页面跳转功能(上一页下一页首页末页页面跳转)
- 自制solidworks图框步骤_solidworks工程图模板制作教程(上) - CAD自学网
- arcgis10.0 sp5下载
- 微信模拟地理位置_微信电脑版伪装地理位置的方法
- Linux初级入门百篇--lsof工具
- python乘法函数_乘积(python乘法函数)
- C++中vector容器和普通数组的区别
- 重装系统lol登录服务器,LOL无法登录的彻底解决方法
- 日本超高人气聊天软件LINE最全注册攻略来了
- 【解题】核电站问题(SGOI)
- HDU 4417 Super Mario(离线线段树or树状数组)