二进制状态压缩枚举子集

对于二进制状态 S S ,可以用此方法不重不漏地枚举出子状态:

for (int sub = S; sub; sub = (sub - 1) & S) {
	// sub 为 S 的子集
}

【证明】 s u b = ( s u b 1 ) S sub = (sub - 1) \cap S 可知 s u b sub 每次必然会变小,于是我们只需要证明区间 ( ( s u b 1 ) S , s u b ) \left((sub - 1) \cap S, sub\right) 中不存在 S S 的子集。设 s u b = ( d 1 d 2 d k 10 0 ) 2 sub = (d_1d_2 \cdots d_k 10 \cdots 0)_2 ,那么 s u b 1 = ( d 1 d 2 d k 01 1 ) 2 sub - 1 = (d_1d_2 \cdots d_k 01 \cdots 1)_2 ,由于 s u b sub S S 的子集,则 ( d 1 d 2 d k 00 0 ) 2 (d_1d_2 \cdots d_k 00 \cdots 0)_2 S S 的子集,因此考虑 ( d 1 d 2 d k 01 1 ) 2 S (d_1d_2 \cdots d_k 01 \cdots 1)_2 \cap S ,得到的一定是 ( ( d 1 d 2 d k 00 0 ) 2 , ( d 1 d 2 d k 10 0 ) 2 ) \left((d_1d_2 \cdots d_k 00 \cdots 0)_2, (d_1d_2 \cdots d_k 10 \cdots 0)_2\right) 中值最大的子集,问题得证。

【时间复杂度】 枚举单个状态的子集复杂度为 O ( 2 m ) O(2^m) m m S S 1 1 的个数)。考虑枚举全集 2 n 1 2^n - 1 的每个子集的子集的时间复杂度: O ( i = 0 n ( C n i 2 i ) ) = O ( ( 1 + 2 ) n ) = O ( 3 n ) O\left(\sum\limits_{i = 0}^{n} \left(C_{n}^{i} \cdot 2^i\right)\right) = O\left((1 + 2) ^ n\right) = O(3^n) (二项式定理: ( 1 + x ) n = i = 0 n ( C n i x i ) (1+x)^n = \sum\limits_{i = 0}^{n} \left(C_{n}^{i} \cdot x^i\right) )。

猜你喜欢

转载自blog.csdn.net/C20190102/article/details/106437473