二进制
枚举子集
复杂度 \(O(子集个数)\)
for (int i = S; i != 0; i = (i - 1) & S) ;
首先& S
可以保证一定是子集
怎么证明一定全部会枚举到呢?
因为\(-1\)会将最小的\(1\)位变成\(0\), 更小的位全部变成\(1\), 因为是最小的\(1\), 所以接下来第一个 十进制数值 更小的子集肯定这一位是\(0\)了, 这样就可以调到接下来那个子集
枚举子集的子集
复杂度 \(O(3 ^ n)\)
for (S in ((1 << n) - 1))
{
for (T in S)
{
...
}
}
直观可以得到一个较松的上界 \(O(4 ^ n)\)
其实对于一个 1 元素有 \(x\) 个的集合, 他的子集有 \(2 ^ x\) 个, 而这样大小为 \(x\) 的集合是 \(\binom{n}{x}\) 个
容易得到:
\[\sum_{x} \binom{n}{x} \cdot 2 ^ x
\]
由二项式定理
\[(1 + x) ^ n = \sum_{i} \binom{n}{i} \cdot x ^ i
\]
可得
在上式中带入 \(x = 2\), 结果 \(= (1 + 2) ^ n = 3 ^ n\)