生成树与prufer序列相互转换的模板:
#include<bits/stdc++.h> using namespace std; const int N=500010; struct node{ int nxt,to; }e[N]; int head[N],cnt,fa[N]; int in[N],P; int deg[N],prufer[N],tot; int n; void add(int from,int to){ e[++cnt].nxt=head[from]; e[cnt].to=to; head[from]=cnt; } void dfs(int from,int F){ fa[from]=F; if(F)deg[from]++; for(int i=head[from];i;i=e[i].nxt){ int to=e[i].to; if(to==fa[from])continue; dfs(to,from); deg[from]++; } } void prufer_encode(){//得到序列长度和prufer序列 memset(fa,0,sizeof fa); memset(prufer,0,sizeof prufer); memset(deg,0,sizeof deg); P=-1,tot=0; dfs(n,0); for(int i=1;i<=n;i++)in[i]=deg[i]; for(int i=1;i<=n;i++)if(in[i]==1){P=i;break;} int now=P; for(int i=1;i<=n-2;i++){ int nxt=fa[now]; prufer[++tot]=nxt; if((--in[nxt])==1&&nxt<now){ now=nxt; }else{ P++; while(in[P]!=1)P++; now=P; } } } void prufer_decode(){//得到prufer序列对应原图以及各点度数 memset(deg,0,sizeof deg); memset(head,0,sizeof head); memset(e,0,sizeof e); cnt=0,n=tot+2,P=-1; for(int i=1;i<=n;i++)deg[i]=1; for(int i=1;i<=tot;i++)deg[prufer[i]]++; for(int i=1;i<=n;i++)in[i]=deg[i]; for(int i=1;i<=n;i++)if(in[i]==1){P=i;break;} int now=P; for(int i=1;i<=n-2;i++){ int nxt=prufer[i]; add(now,nxt); add(nxt,now); if((--in[nxt])==1&&nxt<now){ now=nxt; }else{ P++; while(in[P]!=1)P++; now=P; } } add(now,n); add(n,now); } int main(){ scanf("%d",&n); for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); add(x,y); add(y,x); } prufer_encode(); for(int i=1;i<=tot;i++){ printf("%d ",prufer[i]); } puts(""); prufer_decode(); prufer_encode(); for(int i=1;i<=tot;i++){ printf("%d ",prufer[i]); } puts(""); }
几条定理:
1.Cayley定理:
一个点数为n的完全图有nn-2个生成树
2.一个n个点m条边的带标号无向图有k个连通块,我们希望添加k-1条边使图联通,求方案数:
设第i个连通块的大小为si,
则答案为:
以上具体证明见oiwiki