解析
神题。
把每个节点提到根 rt 单独考虑。
设 dpi,jdp_{i,j}dpi,j 表示当 rt 进入 i 时子树内还有 j 条边未合并的方案的期望之和,gi,jg_{i,j}gi,j 表示当 rt 进入 i 的父亲时 i 的子树内(包括连向父亲的边)还有 j 条边未合并的方案的期望之和。
考虑 (i,fa) 这条边插入的位置,如果在 j 之前,那 rt 将直接从第 j 条边开始受影响;否则,再枚举这条边插入的位置,此时 rt 的存活收到 (i,fa) 这条边的影响,期望要除二。因此有转移:
gi,j=(sizi−j)dpi,j+12∑k=0j−1dpi,kg_{i,j}=(siz_i-j)dp_{i,j}+\frac 1 2\sum_{k=0}^{j-1}dp_{i,k}gi,j=(sizi−j)dpi,j+21k=0∑j−1dpi,k
不难发现各个儿子之间是互不影响的,只要保证 rt 进入子树前后的边顺序不会颠倒即可,就是一个简单的组合数。
n=50n=50n=50 这样的范围可以直接用 double
算组合数。
代码
//luogu
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
using namespace std;const int N=105;
const int mod=1e9+7;
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}inline ll ksm(ll x,ll k){ll res(1);while(k){if(k&1) res=res*x%mod;x=x*x%mod;k>>=1;}return res;
}int n,m;
vector<int>e[N];
double c[N][N],bas;
void init(){c[0][0]=1;for(int i=1;i<=n;i++){c[i][0]=1;for(int j=1;j<=i;j++) c[i][j]=c[i-1][j-1]+c[i-1][j];}bas=1;for(int i=1;i<n;i++) bas=bas*i;return;
}double dp[N][N],g[N][N],tmp[2][N];
int siz[N];
void dfs(int x,int fa){for(int to:e[x]){if(to==fa) continue;dfs(to,x);}siz[x]=0;memset(tmp,0,sizeof(tmp));int now=1,pre=0;tmp[now][0]=1;for(int to:e[x]){if(to==fa) continue;//printf(" %d -> %d\n",x,to);swap(now,pre);memset(tmp[now],0,sizeof(tmp[now]));for(int i=0;i<=siz[to];i++){g[to][i]=(siz[to]-i)*dp[to][i];for(int j=0;j<i;j++) g[to][i]+=dp[to][j]/2;//printf(" i=%d g=%4lf\n",i,g[to][i]);}for(int i=0;i<=siz[to];i++){for(int j=0;j<=siz[x];j++){tmp[now][i+j]+=g[to][i]*tmp[pre][j]*c[i+j][i]*c[siz[to]-i+siz[x]-j][siz[to]-i];}}siz[x]+=siz[to];}siz[x]++;for(int i=0;i<siz[x];i++){dp[x][i]=tmp[now][i];//printf("x=%d i=%d dp=%.4lf\n",x,i,dp[x][i]);}return;
}signed main(){#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);#endifn=read();for(int i=1;i<n;i++){int x=read(),y=read();e[x].push_back(y);e[y].push_back(x);}init();for(int x=1;x<=n;x++){memset(dp,0,sizeof(dp));memset(g,0,sizeof(g));dfs(x,0);printf("%.8lf\n",dp[x][n-1]/bas);}return 0;
}