枚舉大小為k的子集
阿新 • • 發佈:2018-09-23
時間 {} spa 操作 cpp spl span 條件 play
這種位操作不大可能分析出來,先看代碼再分析。
代碼
使用條件:\(k>0\)
void solve(int n,int k)
{
for(int comb = (1 << k) - 1; comb < (1 << n);)
{
// ...
int x = comb & -comb, y = comb + x;
comb = (((comb & ~y) / x ) >> 1) | y;
}
}
證明
\[ \begin{array}{} 首先是輔助變量x,y\x \rightarrow comb最低位\y \rightarrow comb的倒數第一段1取0,該1段前一個位置的0取1\設上述y改變的部分為len\comb\&\sim y \rightarrow len前取0,len中取1,len後取0\(comb\&\sim y)/x \rightarrow 長度為len的全1串\((comb \& \sim y) / x ) >> 1 \rightarrow 右移1位,len-1\綜上\(((comb \& \sim y) / x ) >> 1) | y \rightarrow 把comb的len的前一個位置的0取1,末尾添上len-1個1 \end{array} \]
然後這就是不重不漏的枚舉。
所以時間復雜度\(O\left(\binom{n}{k}\right)\)
枚舉大小為k的子集