二進制狀態壓縮枚舉子集

對於二進制狀態 SS,可以用此方法不重不漏地枚舉出子狀態:

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

【證明】sub=(sub1)Ssub = (sub - 1) \cap S 可知 subsub 每次必然會變小,於是我們只需要證明區間 ((sub1)S,sub)\left((sub - 1) \cap S, sub\right) 中不存在 SS 的子集。設 sub=(d1d2dk100)2sub = (d_1d_2 \cdots d_k 10 \cdots 0)_2,那麼 sub1=(d1d2dk011)2sub - 1 = (d_1d_2 \cdots d_k 01 \cdots 1)_2,由於 subsubSS 的子集,則 (d1d2dk000)2(d_1d_2 \cdots d_k 00 \cdots 0)_2SS 的子集,因此考慮 (d1d2dk011)2S(d_1d_2 \cdots d_k 01 \cdots 1)_2 \cap S,得到的一定是 ((d1d2dk000)2,(d1d2dk100)2)\left((d_1d_2 \cdots d_k 00 \cdots 0)_2, (d_1d_2 \cdots d_k 10 \cdots 0)_2\right) 中值最大的子集,問題得證。

【時間複雜度】 枚舉單個狀態的子集複雜度爲 O(2m)O(2^m)mmSS11 的個數)。考慮枚舉全集 2n12^n - 1 的每個子集的子集的時間複雜度:O(i=0n(Cni2i))=O((1+2)n)=O(3n)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=0n(Cnixi)(1+x)^n = \sum\limits_{i = 0}^{n} \left(C_{n}^{i} \cdot x^i\right))。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章