Problem
-
给定一个(n,m)(n,m)(n,m)的无向图,其中第iii条边联通的概率是WiW_iWi,求这个无向图的期望联通块个数。
-
n≤17,m≤n∗(n−1)2n\le 17, m\le \frac{n*(n-1)}{2}n≤17,m≤2n∗(n−1).
Solution
-
求期望联通块个数,那肯定得单独考虑每个联通块对答案的贡献,这种套路太常见了.
-
我们只需计算出一个联通块它联通的概率,再乘上一个联通块(等价于一个点集)不再联通其他点的概率,累加起来就是答案了.
-
计算前者,我们发现正着做并不好做,所以我们正难则反,考虑这个联通块不连通的概率即可,要计算这个概率,很显然是要枚举最小编号所在的块,这个套路也太常见了,然后计算即可.
-
这里的时间复杂度是O(3n)O(3^n)O(3n)的,因为是枚举子集中的子集.
-
我们把式子列一列,令fif_ifi表示iii这个点集不连通的概率.
-
那么有fi=∑j∈i且j包含i中最后一个1fj∗Pj,i−jf_i=\sum_{j\in i 且 j包含i中最后一个1}f_j * P_{j,i-j}fi=j∈i且j包含i中最后一个1∑fj∗Pj,i−jP[i][j]P[i][j]P[i][j]表示的含义是iii与jjj这个点集没有边相连的概率。
-
显然Pj,i−j=bet(i)bet(j)⋅bet(i−j)P_{j,i-j}=\frac{bet(i)}{bet(j)·bet(i-j)}Pj,i−j=bet(j)⋅bet(i−j)bet(i)bet(i)bet(i)bet(i)则表示iii这个点集内的点都没有边相连的概率。
-
最后calc计算答案也是类似的过程.
Code
#include <cstdio>
#include <cstring>
#define ll long long
#define F(i, a, b) for (ll i = a; i <= b; i ++)
const ll N = 18, M = N * (N - 1) / 2, Mo = 998244353;
ll n, m, u[M], v[M], w[M], vis[N];
ll fa[N], Ans, cnt;
ll get(ll x) {
return !fa[x] ? x : get(fa[x]);
}
void Dfs(ll k, ll G) {
if (k > m) {
memset(vis, 0, sizeof vis), cnt = 0;
F(i, 1, n)
if (!vis[get(i)])
vis[get(i)] = 1, cnt ++;
Ans = (Ans + cnt * G) % Mo;
return;
}
ll t = get(u[k]), tmp = fa[t];
if (t ^ get(v[k]))
fa[t] = get(v[k]);
Dfs(k + 1, (G * (Mo + 1 - w[k])) % Mo);
fa[t] = tmp;
Dfs(k + 1, (G * w[k]) % Mo);
}
int main() {
freopen("fair.in", "r", stdin);
freopen("fair.out", "w", stdout);
scanf("%d%d", &n, &m);
F(i, 1, m)
scanf("%d%d%d", &u[i], &v[i], &w[i]);
Dfs(1, 1);
printf("%d\n", Ans);
}