题面
给一个图,边权为 \([0,1]\) 的均匀分布的随机实数,求期望最小生成树的最大边权。
提示:对于 \(n\) 个 \([0,1]\) 之间的随机变量 \(x_1,x_2,\dots,x_n\) ,第 \(k\) 小的那个的期望值是\(\frac{k}{(n+1)}\)。
\(\text{Solution:}\)
将题意写成数学公式,
在 \(Kruscal\) 的过程中求:
\[
E = \sum_{i=1}^m\frac{i\times P(加入第i条边恰好连通)}{m+1}
\]
提出上面的式子:
\[
\begin{aligned}
E\times (m+1) &= \sum_{i=1}^mi\times P(加入第i条边恰好连通)\&=\sum_{i=1}^mi\times (P(加入i条边使图连通)-P(加入i-1条边使原图连通))\&=\sum_{i=1}^mi\times (1-P(加入i条边使图不连通)-1+P(加入i-1条边使原图不连通))\&=\sum_{i=1}^mi\times (P(加入i-1条边使原图不连通) - P(加入i条边使图不连通))\\end{aligned}
\]
展开,得:
\[
E\times (m+1) = \sum_{i=0}^{m-1}P(加入i条边使图不连通) - m\times P(加入m条边使图不连通)
\]
由于 \(m\times P(加入m条边使图不连通) = 0\) (题目保证连通)
\[
E\times (m+1) = \sum_{i=0}^{m-1}P(加入i条边使图不连通)
\]
设 \(f[S][i]\) 为 \(G(S)\) 中选 \(i\) 条边使原图不连通的方案数.
\(g[S][i]\) 为 \(G(S)\) 中选 \(i\) 条边使原图连通的方案数.
\(ecnt[S]\) 为 \(G(S)\) 中所包含的边数.
然后就可以转移了
首先显然有: \(g[S][i] = C_{ecnt[S]}^{i} - f[S][i]\)
由于联通性的定义为任意两点可以到达,我们考虑钦定一个点,枚举它所能到的点集 \(T\) ,以及它不能到达的点集 \(\complement_{S}^T\), 有转移:
\[
f[S][i] = \sum_{T\subsetneqq S} \sum_{j=0}^{ecnt[T]} g[T][j] \times C_{ecnt[\complement_{S}^T]}^{i-j}
\]
然后就做完了。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
#define LL long long
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define GO debug("GO\n")
inline int rint() {
register int x = 0, f = 1; register char c;
while (!isdigit(c = getchar())) if (c == '-') f = -1;
while (x = (x << 1) + (x << 3) + (c ^ 48), isdigit(c = getchar()));
return x * f;
}
const int N = 12, M = 55;
int n, m;
LL graph[N], cnt[1 << N], ecnt[1 << N], f[1 << N][M], g[1 << N][M];
LL C[M][M];
void init() {
for (int i = 0; i <= m; ++ i) {
C[i][0] = 1;
for (int j = 1; j <= i; ++ j)
C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("xhc.in", "r", stdin);
freopen("xhc.out", "w", stdout);
#endif
n = rint(), m = rint();
init();
for (int i = 0; i < m; ++ i) {
int u = rint(), v = rint(); u--, v--;
graph[u] |= (1 << v);
graph[v] |= (1 << u);
}
for (int i = 0; i < 1 << n; ++ i) {
for (int j = 0; j < n; ++ j)
if (i >> j & 1)
ecnt[i] += __builtin_popcount(graph[j] & i);
ecnt[i] >>= 1;//每条边算了两遍
}
for (int S = 0; S < 1 << n; ++ S) {
if (__builtin_popcount(S) == 1) {
g[S][0] = 1;
continue;
}
for (int T = (S - 1) & S; T; T = (T - 1) & S)//枚举真子集
if (T & (S & -S)) {//联通的定义是两两之间互相可以到达,钦定一个点x,枚举它能到达的点集(T),以及它不能到达的点(S ^ T),这里钦定为lowbit
for (int i = 0; i <= ecnt[T] + ecnt[S ^ T]; ++ i) {
for (int j = 0; j <= min(ecnt[T], 1ll * i); ++ j)
f[S][i] += g[T][j] * C[ecnt[S ^ T]][i - j];
}
}
for (int i = 0; i <= ecnt[S]; ++ i)
g[S][i] = C[ecnt[S]][i] - f[S][i];
}
double ans = 0;
for (int i = 0; i < m; ++ i)
ans += 1.0 * f[(1 << n) - 1][i] / C[m][i];
printf("%.6lf\n", ans / (m + 1));
}
原文地址:https://www.cnblogs.com/HNYLMSTea/p/10606564.html