首页 > 其他分享 >《prufer 序列》小记

《prufer 序列》小记

时间:2023-09-27 20:12:10浏览次数:46  
标签:连通 我们 父亲 编号 序列 prufer 节点 小记

今天模拟赛被卡科技了,学一下这个东西,之前也看到很多次,只不过一直都没学。

算法简介

这是一种可以将带标号的树,转成唯一的整数序列表示的方法。而在“数树”题中也有大用。

算法流程大概是将带标号的 \(n\) 个节点的数用 \([1,n]\) 中的 \(n-2\) 个整数来表示一个树。

也可以理解成完全图的生成树和数列之间的双射。

算法流程

对树建立 \(prufer\) 序

具体什么是 \(prufer\) 序呢,就是每次将编号最小的叶节点取出来删掉,把他的父亲加入 \(prufer\) 序中,然后继续遍历下一个编号最小的叶节点。

所以我们显然用一个堆是能够很轻易的在 \(O(n\log n)\) 的时间复杂度中解决这个问题。

不过还有在线性时间中解决的算法。

1、考虑每次取出最小编号的叶节点,把他删掉。

2、令他父亲度数减一,判断他父亲度数是否为 \(0\) ,若为 \(0\) ,我们判断父亲节点是否编号小与当前节点,若小于,则一定父节点仍然是编号最小的父节点,那么我们就令父节点重复 \(1\) 操作。

这样为什么是对的呢,因为如果父节点小于当前节点编号,那么肯定是最小的,若不小于,那么在之后我们也可以枚举到。

因为每条边只会枚举一次,时间复杂度 \(O(n)\)

点击查看代码
for(int i=1;i<n;++i) {
	scanf("%lld",&fa[i]);
	++deg[fa[i]];
}
for(int i=1;i<=n;++i) {
	int x=i;
	while(deg[x]==0) {
		pru[++tot]=fa[x];
		--deg[fa[x]];
		if(fa[x]>i) break;
		x=fa[x];
	}
}

对 \(prufer\) 序建立树

也和上面很类似,每次我们先找到编号最小的点,那么当前枚举到的 \(prufer\) 序,一定是这个点的父亲,那么我们就令这个点的父亲度数减一,同样判断一下是否小于当前节点,然后依次类推就可以了。

不过要注意,因为编号最大的节点不会被删掉,所以我们要令第 \(n-1\) 个位置的 \(prufer\) 序为 \(n\)

点击查看代码
for(int i=1;i<=n-2;++i) {
	scanf("%lld",&pru[i]);
	++deg[pru[i]];
}
pru[n-1]=n;
int nw=0;
for(int i=1;i<=n;++i) {
	int x=i;
	while(deg[x]==0) {
		fa[x]=pru[++nw];
		--deg[fa[x]];
		if(fa[x]>i) break;
		x=fa[x];
	}
}

\(prufer\) 序的一些性质

  • 一个点的度数是 \(d\) ,那么这个点在 \(prufer\) 序中出现次数为 \(d-1\)

  • 构建 \(prufer\) 序过程中我们会删掉 \(n-2\) 个数,最终剩下两个数中一定有一个数是最大的数。

\(prufer\) 序最常用的还是在数树方面的应用。

  • \(Cayley\) 定理:

大小为 \(n\) 的完全图,有 \(n^{n-2}\) 种不同的生成树。

至于证明是非常容易的,因为我们 \(prufer\) 序每个都对应唯一的一个无根树,然后我们序列长度是 \(n-2\) ,每个位置可以填 \([1,n]\) 所以我们就有 \(n^{n-2}\) 种不同的生成树。

不过更常用的还是下面这个定理:

看这个典题

给一个有 \(n\) 个点,\(m\) 条边,有 \(k\) 个连通块的带标号无向图,添加 \(k-1\) 条边使得图连通,求方案。

我们记 \(s_i\) 为第 \(i\) 个连通块的大小,那么答案就是:

\(n^{k-2}\prod\limits_{i=1}^k s_i\)

对于如何证明,太严谨的证明我不会,不过口糊一下我还是可以的。

我们可以将每个连通块看成一个点。

然后我们对于这些连通块要把它们连通,也就是看成点的情况下变成一棵树,所以我们就要构造一个长度为 \(k-2\) 的 \(prufer\) 序列,每个位置可以选择 \([1,n]\) 中的一个,我们相当于确定了连边中的父亲是谁,所以方案数为 \(n^{k-2}\)

现在我们还要确定每条连边中的儿子是谁,然后实际上因为每个连通块中只有一条连向父亲的边,而这条边中可以在自己连通块中任意选一个边,所以贡献是 \(s_i\)

所以最终答案就是 \(n^{k-2}\prod\limits_{i=1}^k s_i\)

标签:连通,我们,父亲,编号,序列,prufer,节点,小记
From: https://www.cnblogs.com/ddl1no2home/p/17734219.html

相关文章

  • 莫比乌斯反演小记
    基本内容莫比乌斯函数\(\mu\)定义为\(1\)的逆。一些小性质:\(\mu*1=\epsilon\)\(\mu*\text{id}=\varphi\)反演内容我的理解是:\[[a=1]=\sum\limits_{d|a}\mu(d)\]典型例题例1P2398GCDSUM求\[\sum\limits_{i=1}^n\sum\limits_{j=1}^n\gcd(i,j)\]来推下式......
  • 【UVA 536】Tree Recovery 题解(根据遍历序列还原二叉树)
    小瓦伦丁非常喜欢玩二叉树。她最喜欢的游戏是随机构建查找节点中带有大写字母的二叉树。这是她创作的一个例子:为了给后代记录她的树,她为每棵树写下了两个字符串:预订单遍历(根、左子树、右子树)和有序遍历(左子树、根、右子树。对于上面绘制的树,预序遍历是DBACEGF,有序遍历是ABCDEFG......
  • [JSON|序列化] fastjson自定义字段命名规则 (转发)
    1序言博主本人近期也遇到了基于fatsjson自定义命名字段规则的问题,为加强对此的学习和记忆,故转发这篇博文。博主本人最终采取的方法21.1前置知识fastjson在将对象转变为JSON字符串时,字段默认使用CamelCase规则命名。在1.2.15版本之后,fastjson支持配置Proper......
  • Python分享之序列的方法
    任何的序列都可以引用其中的元素(item)。下面的内建函数(built-infunction)可用于序列(表,定值表,字符串):#s为一个序列len(s)    返回:序列中包含元素的个数min(s)    返回:序列中最小的元素max(s)    返回:序列中最大的元素all(s)    返回:T......
  • git blame 用法小记
    1、概述git管理的代码仓库,在协作开发中不可避免地会出现代码冲突,或者有新手错误地提交代码。出现问题不可怕,可怕的是找不到问题出在哪里。有时候找到出问题的代码,却不知道是谁提交的。git提供了一个有用的命令gitblame来帮你查看一个文件的每一行是如何被修改的,以及由谁修改......
  • SpringBoot | Redis序列化与分布式锁
    欢迎参观我的博客,一个Vue与SpringBoot结合的产物:https://poetize.cn博客:https://gitee.com/littledokey/poetize-vue2.git聊天室:https://gitee.com/littledokey/poetize-im-vue3.git后端:https://gitee.com/littledokey/poetize.git七牛云登录/注册地址(文件服务器,CDN):https:/......
  • SpringBoot | Jackson序列化
    欢迎参观我的博客,一个Vue与SpringBoot结合的产物:https://poetize.cn博客:https://gitee.com/littledokey/poetize-vue2.git聊天室:https://gitee.com/littledokey/poetize-im-vue3.git后端:https://gitee.com/littledokey/poetize.git七牛云登录/注册地址(文件服务器,CDN):https:/......
  • 最长上升子序列
    母题求最长上升子序列。令\(f_i\)表示以\(i\)结尾的答案,然后考虑对于\(a_i>a_j,f_i=\max(f_j+1)\)。1类似,但是需要预处理,结构是一样的。2前缀和、差分,还是很类似。3多记录当前选取的子段个数,考虑最后一段选取即可。4状态还是前xxx+“<”个数。考虑新的数放的位置......
  • B3637 最长上升子序列
    B3637最长上升子序列dp模板题以样例124134作为说明每个数都是自己的一个子序列,所以全部初始化为1从1-n开始循环,定下来当前要计算的数i再从1-i开始循环,判断i的最长上升子序列,定为j如果i比j要大,则说明是上升的,此时的长度为i的长度与j的长度+1的最......
  • 浅谈UE4的序列化
    【USparkle专栏】如果你深怀绝技,爱“搞点研究”,乐于分享也博采众长,我们期待你的加入,让智慧的火花碰撞交织,让知识的传递生生不息!一、结合用例浅谈UE4序列化1.1需求我写文章,不爱一上来就讲道理、贴代码,而是喜欢先提需求、提问题,然后围绕这个需求的实现再一步步挖掘源码。我们......