pub fn bit_binom(n: usize, k: usize) -> impl Iterator<Item = usize>
Expand description
組合せのビット表現。
$n$ bit で表せる整数のうち、$k$ 個の bit が 1
であるものを昇順に生成する。
Idea
$k$ 個の bit が 1
である整数 i
が与えられたとき、$k$ 個の bit が 1
である整数のうち i
より大きく最小の整数 j
を考える。
例として i = 011001110
とする。
011001110 // i
^~~~
i
のうちで 1
が連続して現れる部分のうち、最も右のものを考える。
これの左にある 0
の位は、j
においては 1
である必要がある。
011001110 // i
01101.... // j (upper)
また、残った下位の領域においては、i
における 1
の連続個数よりひとつ少ない
1
を右詰めで入れればよい。
011001110 // i
.....0011 // j (lower)
あとは、これらを計算する方法について述べる。
011001110 // i
000000010 // x = i & i.wrapping_neg()
011010000 // y = i + x
000001110 // i & !y
000000011 // z = (i & !y) >> (x.trailing_zeros() + 1)
011010011 // j = y | z
上記では _ >> (x.trailing_zeros() + 1)
としているが、x
が 2
べきなので (_ / x) >> 1
と等しい。
Examples
use nekolib::math::bit_binom;
let mut it = bit_binom(4, 2);
assert_eq!(it.next(), Some(0b_0011));
assert_eq!(it.next(), Some(0b_0101));
assert_eq!(it.next(), Some(0b_0110));
assert_eq!(it.next(), Some(0b_1001));
assert_eq!(it.next(), Some(0b_1010));
assert_eq!(it.next(), Some(0b_1100));
assert_eq!(it.next(), None);
References
- 蟻本 p.144