1. 程式人生 > >枚舉大小為k的子集

枚舉大小為k的子集

時間 {} 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的子集