# BZOJ3925: [Zjoi2015]地震后的幻想乡【概率期望+状压DP】

5 4
1 2
1 5
4 3
5 3

0.800000

## HINT

（以下内容与题意无关，对于解题也不是必要的。）

## 思路

$f_{i,j}$表示点集是i连了j条边不连通的方案数

$g_{i,j}$表示点集是i连了j条边联通的方案数

#include<bits/stdc++.h>

using namespace std;

typedef long double ld;

const int N = (1 << 10) + 10;
const int M = 110;

int n, m, cnt[N], siz[N];
ld c[M][M], f[N][M], g[N][M];

int main() {
scanf("%d %d", &n, &m);
int up = 1 << n;
for (int i = 1; i <= m; i++) {
int u, v; scanf("%d %d", &u, &v);
for (int s = 0; s < up; s++) {
if (!((s >> (u - 1)) & 1)) continue;
if (!((s >> (v - 1)) & 1)) continue;
++cnt[s];
}
}
for (int i = 1; i <= up; i++) {
for (int j = 1; j <= n; j++) {
if ((i >> (j - 1)) & 1) ++siz[i];
}
}
for (int i = 0; i <= m; i++) c[i][0] = 1;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= i; j++) {
c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
}
}
for (int s = 1; s < up; s++) {
if (siz[s] == 1) {
g[s][0] = 1;
continue;
}
int cur = s & (-s);
for (int sub = (s - 1) & s; sub; sub = (sub - 1) & s) if (sub & cur) {
for (int i = 0; i <= cnt[sub]; i++) {
for (int j = 0; j <= cnt[s ^ sub]; j++) {
f[s][i + j] += g[sub][i] * c[cnt[s ^ sub]][j];
}
}
}
for (int i = 0; i <= m; i++) {
g[s][i] = c[cnt[s]][i] - f[s][i];
}
}
ld ans = 0.0;
for (int i = 0; i <= m; i++) {
ans += f[up - 1][i] / c[cnt[up - 1]][i];
}
ans /= m + 1;
printf("%.6Lf", ans);
return 0;
} 
posted @ 2018-12-10 23:24  Dream_maker_yk  阅读(...)  评论(...编辑  收藏