首页 > 其他分享 >2419. prufer序列

2419. prufer序列

时间:2022-12-05 10:24:14浏览次数:60  
标签:根树 int 序列 2419 prufer 节点 define

题目链接

2419. prufer序列

本题需要你实现prufer序列与无根树之间的相互转化。

假设本题涉及的无根树共有 \(n\) 个节点,编号 \(1 \sim n\)。

为了更加简单明了的描述无根树的结构,我们不妨在输入和输出时将该无根树描述为一个以 \(n\) 号节点为根的有根树。

这样就可以设这棵无根树的父亲序列为 \(f_1,f_2,…,f_{n-1}\),其中 \(f_i\) 表示将该树看作以 \(n\) 号节点为根的有根树时,\(i\) 号节点的父节点编号。

同时,设这棵无根树的prufer序列为 \(p_1,p_2,…,p_{n-2}\)。

现在,给定一棵由 \(n\) 个节点构成的无根树,以及该无根树的一个序列(父亲序列或prufer序列),请你求出另一个序列。

输入格式

输入共两行。

第一行包含两个整数 \(n,m\),表示无根树的节点数以及给定序列类型。

如果 \(m = 1\),则第二行包含 \(n-1\) 个整数,表示给定序列为父亲序列。

如果 \(m = 2\),则第二行包含 \(n-2\) 个整数,表示给定序列为prufer序列。

输出格式

共一行,输出另一个序列,整数之间用单个空格隔开。

数据范围

\(2 \le n \le 10^5\)

输入样例1:

6 1
3 5 4 5 6

输出样例1:

3 5 4 5

输入样例2:

6 2
3 5 4 5

输出样例2:

3 5 4 5 6

解题思路

prufer编码

prufer编码主要作用即将一棵无根树转化为一个序列(即prufer序列),另外prufer序列也可以反过来转化为一棵树,即prufer序列和树之间是一一对应的,常用来解决一些证明问题,如凯莱定理等
证明凯莱定理(一个无向完全图有 \(n^{n-2}\) 棵生成树):由于prufer序列和树之间是一一对应的关系,证明有多少棵不同的生成树即证明有多少种prufer序列,显然,prufer序列共有 \(n-2\) 项,其范围为 \(1\sim n\),故其种类数为 \(n^{n-2}\)

prufer编码的流程:假定 \(n\) 号节点为根,找到除根外度数最小的节点,在删除该节点之前,将其父节点输出,重复该流程,直到最后只剩下两个节点,即prufer序列只有 \(n-2\) 个元素,因为prufer序列最多 \(n-1\) 个元素,而最后一个元素一定为 \(n\),所以这个元素可以省略,输出的元素即为prufer序列
\(\color{red}{如何将一棵树线性时间内转化为prufer序列?}\)
假定当前出度为 \(0\) 且编号最小的节点为 \(j\),则输出 \(f[j]\),删除 \(j\) 之后,出度为 \(0\) 的节点至多只会增加一个,即 \(f[j]\),判断删除 \(j\) 之后 \(f[j]\) 的出度是否为 \(0\),如果 \(f[j]\) 的出度为 \(0\) 且 \(f[j]<j\) 说明 \(f[j]\) 是当前出度为 \(0\) 且编号最小的节点,递归输出这样的父节点即可,否则说明这样的 \(j\) 只会更大,即 \(j\) 只会增加,这样即可线性时间内将一颗树转化为prufer序列

\(\color{red}{如何将一个prufer序列转化为一棵树?}\)
先将 \(n\) 这个节点加入到prufer序列中,不难发现,prufer序列中某个数出现的次数即为该数在树中的儿子节点的数量,从 \(1\) 开始找到儿子数量为 \(0\) 且编号最小的节点 \(j\),其父节点即为当前遍历的prufer序列的元素,将该元素从prufer序列中删去,因为删除该元素后儿子数量为 \(0\) 的节点数量至多直接增加一个,如果该元素的儿子数量为 \(0\) 且编号小于 \(j\),说明当前节点即为儿子数量为 \(0\) 且编号最小的节点,递归处理即可,这样的 \(j\) 同样也是递增的,故可以在线性时间内将一个prufer序列转化为一棵树

  • 时间复杂度:\(O(n)\)

代码

// Problem: prufer序列
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/2421/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=1e5+5;
int n,m;
int f[N],p[N],d[N];
void tree2prufer()
{
	for(int i=1;i<n;i++)
	{
		scanf("%d",&f[i]);
		d[f[i]]++;
	}
	for(int i=0,j=1;i<n-2;j++)
	{
		while(d[j])j++;
		p[i++]=f[j];
		while(i<n-2&&--d[p[i-1]]==0&&p[i-1]<j)p[i++]=f[p[i-1]];
	}
	for(int i=0;i<n-2;i++)printf("%d ",p[i]);
}
void prufer2tree()
{
	for(int i=1;i<=n-2;i++)
	{
		scanf("%d",&p[i]);
		d[p[i]]++;
	}
	p[n-1]=n;
	for(int i=1,j=1;i<n;i++,j++)
	{
		while(d[j])j++;
		f[j]=p[i];
		while(i<n&&--d[p[i]]==0&&p[i]<j)f[p[i]]=p[i+1],i++;
	}
	for(int i=1;i<n;i++)printf("%d ",f[i]);
}
int main()
{
    scanf("%d%d",&n,&m);
    if(m==1)tree2prufer();
    else
    	prufer2tree();
    return 0;
}

标签:根树,int,序列,2419,prufer,节点,define
From: https://www.cnblogs.com/zyyun/p/16951582.html

相关文章

  • 零基础学python 第四章 序列的应用
    实例1 输出每日一贴importdatetimemot=["今天星期一:\n坚持下去不是因为我很坚强,而是因为我别无选择。","今天星期二:\n含泪播种的人一定能笑着收获。",......
  • 动态规划_最长公共子序列
    '示例1:输入:text1="abcde",text2="ace"输出:3解释:最长公共子序列是"ace",它的长度为3。'示例2:输入:text1="abc",text2="abc"输出:3解释:最长公共子序列是......
  • 每日算法之栈的压入、弹出序列
    JZ31栈的压入、弹出序列描述输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,......
  • Nucmer+LINKVIEW实现序列水平的共线性分析
    https://www.cnblogs.com/johnsonzzz/p/15151634.htmlhttps://github.com/YangJianshun/LINKVIEW可以绘制两个基因组、三个基因组的染色体水平的共线性关系。按染色体配......
  • 时间序列分析 2.X 单位根检验
    单位根检验(基于模型检验序列是否平稳)趋势平稳序列\(X_{t}=\beta_{0}+\beta_{1}t+Y_{t}\)\(Y_t\)为平稳序列,则称\(X_t\)为趋势平稳序列差分平稳序列如果......
  • 最长回文子序列
    1.动态规划代码问题:dp[i][j]:是否为回文串(以i开头,以j结尾)最优子:dp[i][j]=dp[i+1][j-1]若开头和结尾元素相等,并且中间也是回文,那么dp[i][j]也是回文记录长度:ans;记录开头:ret......
  • 【ARIMA时序预测】基于ARIMA实现时间序列数据预测附matlab代码
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进。......
  • 最长上升子序列(字符串+路径追溯版)
    1#include<bits/stdc++.h>2usingnamespacestd;34#defineintlonglong56#ifdefLOCAL7#include"algo/dbg.h"8#else9#definedebug(...)4......
  • 笔记:序列的修改、散列和切片
    fromarrayimportarrayimportreprlib,math,numbersfromfunctoolsimportreducefromoperatorimportxorfromitertoolsimportchain#Vector_v1classVect......
  • 多元时间序列特征工程的指南
    使用Python根据汇总统计信息添加新特性,本文将告诉你如何计算几个时间序列中的滚动统计信息。将这些信息添加到解释变量中通常会获得更好的预测性能。简介自回归多变量时......