Prufer 序列

Prufer 序列

一棵有标号无根树可以与它的 Prufer 序列唯一对应,通过生成 / / / 还原方法可以了解为什么一一对应。

树 - Prufer 序列

将编号最小的叶子节点删除,然后将它的父节点的编号记录在序列尾部,重复执行直到树只有一个节点,如此得到的序列即为它的 Prufer 序列。

实现

显然的实现方法是使用一个优先队列,时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

但还有线性做法:用一个指针 j j j 表示最小的叶子节点,删掉 j j j 节点。如果删掉 j j j 节点后,它的父亲 k k k 变为了叶子且 k < j k < j k<j,则删掉 k k k,如果 k k k 的父亲编号仍然比 j j j 小,重复上述过程。每次删完节点记录对应父节点的编号即可。 j j j 的移动是单调的,因此时间复杂度 O ( n ) O(n) O(n)

代码(Deg 儿子个数数组,Pru Prufer 序列,Par 父亲数组):

for (int i = 1, j = 1; i <= N - 2; i++, j++) {
// j 是最小叶节点的编号, i 是当前 Prufer 序列末尾位置
	while (Deg[j]) j++;
	Pru[i] = Par[j];
	while (i < N - 2 && --Deg[Pru[i]] == 0 && Pru[i] < j)
		Pru[i + 1] = Par[Pru[i]], i++; // Pru[i] 即为上文中的 k
}

Prufer 序列 - 树

即 树 - Prufer 序列 的逆变换。

实现

一个数在 Prufer 序列中出现的次数就是这个编号节点在树上的儿子个数,用 j j j 表示未出现过的最小编号节点,当前 Prufer 序列首元素即为点 j j j 的父亲,然后删掉 Prufer 序列首元素且其儿子个数减一,如果该元素变为了叶节点,用上文类似的方法循环处理即可。

代码(节点个数 N 为根):

Pru[N - 1] = N; // 最后一个节点删掉后,根 N 视为它的父亲
for (int i = 1, j = 1; i < N; i++, j++) { // i 是当前 Prufer 序列首元素下标
	while (Deg[j]) j++;
	Par[j] = Pru[i];
	while (i < N && --Deg[Pru[i]] == 0 && Pru[i] < j)
		Par[Pru[i]] = Pru[i + 1], i++;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值