2019 牛客多校第五场 E - independent set 1

题目链接:2019 牛客多校第五场 E

最多 26 个点,\(2^n \approx 6 \times 10^7\),考虑用二进制压缩状态。状态 \(s\) 的第 \(i\) 位表示取或者不取第 \(i\) 个点。

我们用 \(f(s)\) 表示状态 \(s\) 的最大独立集的个数,可以从下面两个状态推得:二进制 \(s\) 的最后一个为1的位置不属于最大独立集 \(f(s) = f(s - {\rm lowbit}(s) )\) 二进制 \(s\) 的最后一个为1的位置属于最大独立集 \(f(s) = f(s - {\rm adj}(u)) + 1\) 其中 \({\rm adj}(u)\) 表示最后一个为 1 的位置和它相邻节点的集合,即 \(v\) 在最大独立集中,则与它邻接的点一定不在最大独立集中。二者取最大即可。

时间复杂度 \(O(2^n)\)

需要特别注意这题空间卡得很紧,需要用 char 来存答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAX_N = 26;
const int MAX_S = (1 << 26);
int n, m, all;
vector <int> g[MAX_N];
int c[MAX_N];
char f[MAX_S];
char dfs(int s) {
if (f[s] != -1) return f[s];
int u = s, pos = 0;
while (!(u & 1)) ++pos, u >>= 1;
short notInSet = dfs(s - (1 << pos));
short inSet = 1 + dfs(s & c[pos]);
f[s] = max(inSet, notInSet);
return f[s];
}
int main() {
scanf("%d%d", &n, &m);
all = (1 << n) - 1;
int u, v;
for (int i = 1; i <= m; ++i) {
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
for (int i = 0; i < n; ++i) {
c[i] += (1 << i);
for (auto const &e: g[i]) {
c[i] += (1 << e);
}
c[i] = c[i] ^ all;
// printf("%d>", i), printBit(c[i]), putchar('>'), printBit(c[i] ^ all), puts("");
}
fill(f, f + MAX_S, -1);
f[0] = 0;
LL ans = 0;
for (int i = 0; i <= all; ++i) ans += int(dfs(i));
printf("%lld\n", ans);
return 0;
}