题解
\(O(n \cdot 3^n)\) 的 DP 应该很好想,考虑一下怎么优化状态。
令 \(max_{s}\) 表示集合 \(s\) 取到的最大独立集大小,令 \(dp_{s}\) 表示集合 \(s\) 取到对应的最大独立集的概率 然。
枚举一下 \(s\) 中最后加入独立集的数是哪个,把 \(s\) 中和 \(i\) 有连接的都删掉,然后转移,时间复杂度 \(O(n \cdot 2^{n})\)。
#include <bits/stdc++.h>
using namespace std;
const int md = 998244353;
const int N = 20;
void add(int &a, int b) {
a += b;
if (a >= md) {
a -= md;
}
}
int mul(int a, int b) {
return (long long) a * b % md;
}
int n, m, g[N], inv[N + 10], f[1 << N], mx[1 << N], l2[1 << N];
int main() {
scanf("%d %d", &n, &m);
for (int i = 0; i < n; i++) {
g[i] = 1 << i;
}
for (int i = 0; i < m; i++) {
int x, y;
scanf("%d %d", &x, &y);
x--; y--;
g[x] |= 1 << y;
g[y] |= 1 << x;
}
inv[1] = 1;
for (int i = 2; i <= n; i++) {
inv[i] = mul(md - md / i, inv[md % i]);
}
for (int i = 0; i < n; i++) {
l2[1 << i] = i;
}
f[0] = 1;
mx[0] = 0;
const int S = (1 << n) - 1;
for (int v = 1; v <= S; v++) {
int pop = 0;
int t = v;
while (t > 0) {
int i = l2[t & -t];
int u = v & (~g[i]);
if (mx[u] + 1 == mx[v]) {
add(f[v], f[u]);
} else if (mx[u] + 1 > mx[v]) {
mx[v] = mx[u] + 1;
f[v] = f[u];
}
t -= t & -t;
pop++;
}
f[v] = mul(f[v], inv[pop]);
}
printf("%d\n", f[S]);
return 0;
}