题目:http://www.lydsy.com/JudgeOnline/problem.php?
题意:给定一个
题解:依据期望的线性性,我们能够算出随机选前
此题略卡精度。所以我们能够考虑先算出可行方案数。再除以总方案数得到概率。
令
对于计算
这个转移能够通过对子集的枚举做到
令全集为
这样做用
double
就能够保证精度了,无需__float128
。
代码:
#include <cstdio>
const int maxn = 11, maxm = 46;
int n, m, e[maxn], sz[1 << maxn], cnt[1 << maxn];
long long c[maxm][maxm], f[1 << maxn][maxm], g[1 << maxn][maxm];
double ans;
int main()
{
scanf("%d%d", &n, &m);
for(int i = 0; i < m; ++i)
{
int u, v;
scanf("%d%d", &u, &v);
--u;
--v;
e[u] |= 1 << v;
e[v] |= 1 << u;
}
c[0][0] = 1;
for(int i = 1; i <= m; ++i)
{
c[i][0] = c[i][i] = 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)
{
sz[s] = sz[s >> 1] + (s & 1);
if(sz[s] == 1)
{
g[s][0] = 1;
continue;
}
for(int i = 0; i < n; ++i)
if((s >> i) & 1)
cnt[s] += sz[e[i] & s];
cnt[s] >>= 1;
int lowbit = s & -s;
for(int t = (s - 1) & s; t; t = (t - 1) & s)
if(t & lowbit)
for(int i = 0; i <= cnt[t]; ++i)
for(int j = 0; j <= cnt[s ^ t]; ++j)
f[s][i + j] += g[t][i] * c[cnt[s ^ t]][j];
for(int i = 0; i <= cnt[s]; ++i)
g[s][i] = c[cnt[s]][i] - f[s][i];
}
for(int i = 0; i <= m; ++i)
ans += (double)f[(1 << n) - 1][i] / c[cnt[(1 << n) - 1]][i];
ans /= m + 1;
printf("%.6f\n", ans);
return 0;
}