luogu-P3343题解
简要题意
给定一张 \(n\) 个点 \(m\) 条边的图,边的边权是 \([0, 1]\) 之间均匀分布的随机实数,且相互独立。求最小生成树的最大边权的期望值。
思路
首先有一个比较神秘的跟概率有关的东西,虽然题面中已经给出提示,但这里还是进行简单说明:
引理:将长度为 \(n\) 的区间随机划成 \(m\) 段,每段长度期望是 \(n\over m\)。
笔者询问 deepseek,deepseek 给出了三种证明方法,在此仅给出笔者知道的一种。
我们设第 \(i\) 段长度为 \(L_i\),就有:\(n=\sum\limits_{i=1}^mL_i\)。
根据期望的线性性和对称性我们可以得到:\(n=E(\sum\limits_{i=1}^mL_i)=\sum\limits_{i=1}^mE(L_i)\) 和 \(L_1=L_2=\dots=L_m\)。
所以 \(E(L_i)={n\over m}\)。
所以第 \(k\) 大的边贡献就是 \(k\over m+1\)。我们首先能够有一个 naive 的想法,枚举每个边的大小关系,然后暴力跑 kruskal。这个想法可以启发我们去思考如何统计所有第 \(k\) 大的边的贡献。
首先看每种情况做贡献的概率,确定了选择哪些边要选和哪个边做贡献后就好做了,有 \(P={(k-1)!(m-k)!\over m!}\)。因为期望等于总方案数除以概率,所以现在我们只需要去找方案数,这个就 dp 去求。
因为恰好选第 \(k\) 大的边使图连通不好描述,所以容斥,变成选第 \(k\) 大的边前图不连通的方案数减去选第 \(k\) 大的边后图不连通的方案数。于是就有一个 dp,设 \(f_{S,i}\) 表示 \(S\) 构成的点集中选 \(i\) 条边图不连通的方案,现在考虑枚举子集进行转移。转移就从若干已经连通的子图中选出剩下的一些边,但是不能使整个图连通,所以从严格意义上说是枚举真子集。所以引入 \(g_{S,i}\) 表示 \(S\) 构成的点集中选 \(i\) 条边图连通的方案,就有下面两个转移式:
其中 \(d_S\) 为 \(S\) 的导出子图。
最后的答案就是:
化简得:
代码
signed main(){
n = rd(), m = rd();
for(int i = 1, u, v; i <= m; ++i)u = rd(), v = rd(), ++mp[(1 << u - 1) | (1 << v - 1)];
for(int S = 1; S < (1 << n); ++S)for(int T = S; T; T = T - 1 & S)d[S] += mp[T];
c[0][0] = c[1][0] = 1;
for(int i = 1; i <= m; c[++i][0] = 1)for(int j = 1; j <= i; ++j)c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
for(int S = 1; S < (1 << n); ++S)for(int i = 0; i <= d[S]; ++i){
for(int T = S & S - 1; T; T = T - 1 & S)if(T & (S & - S))
for(int j = 0; j <= min(i, d[T]); ++j)f[S][i] += g[T][j] * c[d[S ^ T]][i - j];
g[S][i] = 1.0 * c[d[S]][i] - f[S][i];
}
for(int i = 0; i <= m; ++i)ans += f[(1 << n) - 1][i] / c[m][i];
ans /= 1.0 + m;
printf("%.6f", ans);
return 0;
}

浙公网安备 33010602011771号