Prufer序列是一种将树和序列双向映射的方式
构造方法:
- 统计树上结点的度数 \(degree_i\)
- 找到所有叶子结点 \((degree_i==1)\) 中编号最小的 \(x\),输出 \(fa_x\)
- 将 \(fa_x\) 的度数减 \(1\)
- 重复步骤 \(2-3\),直到只剩下 \(n-2\) 个元素为止
性质:
- 树上结点编号在prufer序中出现的次数为 \(degree_x-1\) 次
- 最后剩下的 \(2\) 个点中,一定包含编号为 \(n\) 的结点
下面为获得prufer序的代码:
void to_prufer()
{
int cur;
for(int i=1;i<=n;i++)if(du[i]==1)
{
cur=i;
break;
}
int leaf=cur;
for(int i=1;i<=n-2;i++)
{
int f=fa[leaf];
prufer[i]=f;
du[f]--;
if(du[f]==1 && f<cur)
{
leaf=f;
continue;
}
cur++;while(du[dur]!=1) cur++;
leaf=cur;
}
}
//要以n为根
下面为获得树的代码:
void to_tree()
{
for(int i=1;i<=n;i++) du[i]=1;
for(int i=1;i<=n-2;i++) du[prufer[i]]++;
int cur;
for(int i=1;i<=n;i++)if(du[i]==1)
{
cur=i;
break;
}
int leaf=cur;
for(int i=1;i<=n-2;i++)
{
int f=fa[leaf]=prufer[i];
du[f]--;
if(du[f]==1 && f<cur)
{
leaf=f;
continue;
}
++cur;while(du[cur]!=1) cur++;
leaf=cur;
}
fa[leaf]=n;
}
应用:
- \(n\) 个点的无向完全图的不同生成树的个数 \(n^{n-2}\)
- \(n\) 个点的无根树的方案数 \(n^{n-2}\)
- \(n\) 个点的有根树的方案数 \(n^{n-1}\)
- \(n\) 个点,第 \(i\) 个点的度数为 \(degree_i\) 的无根树的方案数 \(\frac{(n-2)!}{\prod_{i=1}^{n}{(degree_i-1)!}}\)