Prufer序列
无根树与序列的转化
定义为根
编码:给定一个的父亲序列,转化为的prufer序列
解码:给定的prufer序列,还原无根树
cpp
struct Prufer{
// 1-indexed,root=n
vector<int> par,deg;
vector<vector<int>> adj;
int n;
Prufer(int n):n(n),par(n+1,-1){
adj.assign(n+1,{});
deg.assign(n+1,0);
}
void addEdge(int u,int v){
adj[u].push_back(v);
adj[v].push_back(u);
}
void dfs(int u,int fa){
par[u]=fa;
for(auto v:adj[u]){
if(v==fa)continue;
dfs(v,u);
}
}
vector<int> encode(const vector<int>& Par){
vector<int> par=Par;
for(int i=1;i<n;i++)++deg[par[i]];
vector<int> p(n+1);
for(int i=1,j=1;i<=n-2;i++,j++){
while(deg[j])++j;
p[i]=par[j];
while(i<=n-2&&!--deg[p[i]]&&p[i]<j)p[i+1]=par[p[i]],i++;
}
return p;
}
vector<int> encode(){
clear();
dfs(n,0);
return encode(par);
}
vector<int> decode(const vector<int>& P){
clear();
vector<int> p=P;
for(int i=1;i<=n-2;i++)++deg[p[i]];
p[n-1]=n;
vector<int> par(n+1);
for(int i=1,j=1;i<n;i++,j++){
while(deg[j])++j;
par[j]=p[i];
while(i<n&&!--deg[p[i]]&&p[i]<j)par[p[i]]=p[i+1],i++;
}
return par;
}
void clear(){
for(int i=1;i<=n;i++)adj[i].clear();
par.assign(n+1,-1);
deg.assign(n+1,0);
}
};性质
- Cayley公式:完全图有颗生成树
- prufer序列与无根树一一对应
- 度数为的点出现次
- 给定度数序列,答案是
- 个数全排列,然后有个相同的数,去重
图联通方案数
个点条边的无向图有个连通块,希望添加条边使得整个图连通,求方案数
设是第个连通块的点数
答案就是
感性理解:个连通块缩成一个点,生成树有种,每个连通块任选一个点作为连接点,
一些度数已知,一些未知,求生成树方案数
设一直度数有个,
从个位置选择个位置,全排列方案为
剩下个位置,每个位置有种可能,总答案