博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
补坑:Prufer 编码总结
阅读量:5106 次
发布时间:2019-06-13

本文共 3169 字,大约阅读时间需要 10 分钟。

\(Prufer\) 编码

我们希望有一个探究无根树之间的关系的工具。这里我们要讨论的工具就是Prufer编码

简介

prufer编码是一种无根树的编码方式,一个prufer编码对应唯一一颗无根树,且一颗无根树对应唯一一个prufer编码

注意这里,我们认为两颗无根树不同,当且仅当他们的连边情况不同。同构的两颗无根树是可能不同


算法

将树化为Prufer编码

按照以下方式运作

TREE << input;for i = TREE.min_leaf : TREE.size > 2    PRUFER_SEQUENCE.push_back = i.adjacent;    TREE.remove_node:i;output << PRUFER_SEQUENCE;

将Prufer编码化为树

按照以下方式运作

PRUFER_SEQURENCE << input;for i = PRUFER_SEQUENCE.elements    j = [UNIVERSE - PRUFER_SEQUENCE].min;    TREE.link: i, j;    UNIVERSE -= j;    PRUFER_SEQUENCE.pop_head;TREE.link: [UNIVERSE:1], [UNIVERSE:2]; #two elements leftoutput << TREE

证明

可以看到对于一个树的输入,可以得到唯一的编码输出,对于唯一的编码输入也可以得到唯一的树的输出。关键是证明对于一个编码输出,只会有唯一的树的输入。

递归的考虑当前构造出的子图,设\(n\)节点无根树\(A,B\)拥有相同的编码设为\(p\),设\(A',B'\)\(A,B\)当前构造出的子图。当前考虑到了第\(i\)位,那么{\(p_i\)\(p_n\)}={\(A'\)\(B'\)的非叶节点},就是说{\(A'\)的非叶节点}={\(B'\)的非叶节点}。那么最小叶节点也是一定的,与其的连边也是确定的。则确定了\(n-2\)条边。那么我们也能够知道图中最后剩下的两个节点,确定他们之间的边,则确定了全部的\(n-1\)条边。

推广

  1. 编码中节点出现次数就是原树该点的度数-1
  2. \(Cayley\)公式: 对于n个节点的完全图\(K_n\),有\(n^{n-2}\)颗生成树

请读者自行证明

例题

给你一个树每个点的度数限制,求方案数。

推广2,利用prufer编码,转化为一个直观的排列组合问题:\(n-2\)个prufer编码的位置上分配不同个数的点的方案数。其中m个节点不限制度数。下面给出式子:

\[ Answer = [\prod^{n-m}_{i=1} \binom{d_i}{n-2-\sum^{i-1}_{j=1}d_j}]*[m^{n-2-\sum^{n}_{i=1}d_i}] \]
\[ = [\prod^{n-m}_{i=1} \frac{(n-2-\sum^{i-1}_{j=1}d_j)!}{d_i!(n-2-\sum^{i}_{j=1}d_j)!}]*[m^{n-2-\sum^{n}_{i=1}d_i}] \]

\[ = \frac{(n-2)!}{[\prod_{i=1}^{n-m}d_i!]*(n-2-\sum_{i=1}^{n-m}d_i)!}*m^{n-2-\sum^{n-m}_{i=1}d_i} \]

需要高精,即除法以约去质因数为替。

代码如下:

#include 
#include
#include
const int N = 1010, W = 1000000;int ans[N],f[N][N],p[N],prime[N],d[N],tot,n,m,sum,cnt,i,j,x,head;bool check[N];void mul(int k){ for(int i = 0;i <= head;i ++)ans[i] *= k; for(int i = 0;;++i>head?head++:i) { if(i==head && ans[i]
=W){ans[i+1]+=ans[i]/W, ans[i]%=W;} }}int main(){ scanf("%d",&n); if(n==1) { scanf("%d",&x); if(x==0)printf("1\n"); else printf("0\n"); return 0; } for(int i = 0;i < n;i ++) { scanf("%d",&x); if(x==0){printf("0\n");return 0;} if(x==-1)m++;else {d[cnt++]=x-1;sum+=x-1;} } if(sum>n-2){printf("0\n");return 0;} ans[0] = 1; for(int i = 2;i <= n;i ++) { if(!check[i])prime[tot++] = i; for(int j = 0;j < tot;j++) { if(prime[j]*i>n)break; check[prime[j]*i] = true; if(i%prime[j]==0)break; } } for(int i = 2;i <= n;i ++) for(int j = 0;j < tot;j++) { int x = i; while(x%prime[j]==0){x/=prime[j];f[i][j]++;} f[i][j] += f[i-1][j]; } int q = sqrt(n); for(int i = 0;i < tot;i ++)p[i] = f[n-2][i]; d[cnt++] = n-2-sum; for(int i = 0;i < cnt;i ++) for(int j = 0;j < tot;j ++) p[j] -= f[d[i]][j]; for(int i = 0;i < tot;i ++) for(int j = 0;j < p[i];j++) mul(prime[i]); for(int i = 0;i < n-2-sum;i ++) mul(m); for(int i = head;~i;i --) if(i==head)printf("%d",ans[i]); else printf("%06d",ans[i]); printf("\n"); return 0;}

天哪,丑的我自己都看不下去了。。。

参考


待续未完

我现在只写了这一道prufer的题啊,下次遇到继续更新!

转载于:https://www.cnblogs.com/jeff-serval/p/7053681.html

你可能感兴趣的文章
中国烧鹅系列:利用烧鹅自动执行SD卡上的自定义程序(含视频)
查看>>
Solaris11修改主机名
查看>>
latex for wordpress(一)
查看>>
如何在maven工程中加载oracle驱动
查看>>
Flask 系列之 SQLAlchemy
查看>>
iframe跨域与session失效问题
查看>>
aboutMe
查看>>
【Debug】IAR在线调试时报错,Warning: Stack pointer is setup to incorrect alignmentStack,芯片使用STM32F103ZET6...
查看>>
一句话说清分布式锁,进程锁,线程锁
查看>>
Hash和Bloom Filter
查看>>
SQL Server获取月度列表
查看>>
python常用函数
查看>>
python 描点画圆
查看>>
FastDFS使用
查看>>
服务器解析请求的基本原理
查看>>
pycharm 如何设置方法调用字体颜色
查看>>
VUE源码解析心得
查看>>
[HDU3683 Gomoku]
查看>>
【工具相关】iOS-Reveal的使用
查看>>
整体二分——[Poi2011]Meteors
查看>>