我正在研究树搜索算法,其中我使用通过位集表示的元素的二元组,即位集1000101
表示二元{0,2,6} {1,3,4,5}
。
目前,我只是通过递增一个位集迭代所有的二分法,即迭代集合{0,1,2,3}
的所有二分区,我从0001
(包括)转到1000
(不包括)
由于我的算法有时会让我在找到合适的分区时“快速失败”,我想重新排序它们,以便我先看看更平衡的分区。
因此,我想询问是否有人知道从1到2 ^ k的数字的排列,其中min(#set bits,#unitset)或多或少只会减少,仍然可以有效地计算
由于这是一种启发式方法,我不是在寻找确切的结果,只是一种加快算法速度的方法。
答案 0 :(得分:2)
罗里的评论让我朝着正确的方向前进:
如果我们从bitset中的固定数量的一开始,我们可以使用一些比特麻烦的黑客来简单地迭代所有这些。
首先从0...01...1
开始使用k/2
,然后使用k/2 - 1
,k/2 - 2
依此类推。
对于每个起始值,使用Gosper's Hack迭代所有可能的位集排列,直到我们到达bitset的边界。
一个简单的实现可能如下所示(对于k <= 63
)
for (int i = k / 2; i > 0; --i) {
// start with 0 ... 0 1 ... 1 (i times)
unsigned int v = (1 << i) - 1;
// first bitset that doesn't represent a valid bipartition
unsigned int end = 1 << k;
// without this, we would count some bipartitions twice for k even
if (k % 2 == 0 && i == k / 2) end >>= 1;
while(v < end) {
// do something with v...
// iterate to the lexicographically next permutation
unsigned int t = v | (v - 1);
v = (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctz(v) + 1));
}
}