列举所有长度为n和重量的二元数量,最多是k词典
我正在寻找一种算法,该算法列举了给定长度的所有二进制n
词典,并限制了每个数字都被跳过,其中具有锤击权重> k
,对于给定的k
。
例如:对于n = 4
和k = 2
:
0000
0001
0010
0011
0100
0101
0110
---- skipped
1000
1001
1010
---- skipped
1100
---- skipped
---- skipped
---- skipped
当然,最直截了当的方法是在每个循环中添加1个,并检查锤子的重量是否结束阈值。但是,对于较大的n
,您跳过的元素数量增加,因此检查每个数字的开销也在增加。因此,我也在寻找一种有效的方法来做到这一点。
更新: 我以迭代的方式重复了 @500-Internal-Server-Error,如下所示,
uint64_t update_stack(uint32_t *stack, uint32_t *sp, const uint64_t n, const uint64_t k) {
if (stack[*sp] == k) {
uint32_t i = *sp + 1;
// walk up
while (stack[i] == k)
i += 1;
// update
stack[i] += 1;
const uint32_t val = stack[i];
const uint32_t altered_sp = i;
// walk down
while (i > 0) {
stack[i - 1] = val;
i -= 1;
}
// fix up stack pointer
*sp = 0;
return (1ull << (altered_sp + 1)) - 1;
} else {
stack[*sp] += 1;
return 1ull;
}
}
void Generate(const uint64_t n, const uint64_t k) {
uint32_t *stack = (uint32_t *)calloc(n-k+1, sizeof(uint32_t));
uint32_t sp = 0;
uint64_t ctr = 0;
while (ctr < (1ull << n)) {
// number of k windows the algorithm walks through.
const uint64_t limit = k+1-stack[sp];
//print_stack(stack, n, k);
for (uint64_t cw = limit; cw > 1; --cw) {
// start printing
const uint64_t nr_steps = (1ull << cw) - 1ull;
for (uint64_t i = 0; i < nr_steps; ++i) {
f(ctr++);
}
// skip
const uint64_t nr_skip = update_stack(stack, &sp, n, k);
ctr += nr_skip;
}
f(ctr++);
const uint64_t nr_skip = update_stack(stack, &sp, n, k);
ctr += nr_skip;
}
free(stack);
}
这很难,但最终奏效了。我还添加了a benchmark 适用于每个有效值,与幼稚方式相比的加速度。对于n = 20
和k = 3
它的150倍(取决于f)。
I'm looking for an algorithm which enumerates all binary numbers of a given length n
lexicoraphically, with the constraint that every number is skipped, which has a hamming weight > k
, for a given k
.
For example: for n=4
and k=2
:
0000
0001
0010
0011
0100
0101
0110
---- skipped
1000
1001
1010
---- skipped
1100
---- skipped
---- skipped
---- skipped
of course the most straight forward way would be to add 1 in every loop iterations and check if the hamming weight is over the threshold. But for larger n
the number of elements you skip increases, so the overhead of checking every number is increasing too. So I'm also looking for an efficient way to do this.
Update:
I reemplented @500-internal-server-error in a iterative way as follows
uint64_t update_stack(uint32_t *stack, uint32_t *sp, const uint64_t n, const uint64_t k) {
if (stack[*sp] == k) {
uint32_t i = *sp + 1;
// walk up
while (stack[i] == k)
i += 1;
// update
stack[i] += 1;
const uint32_t val = stack[i];
const uint32_t altered_sp = i;
// walk down
while (i > 0) {
stack[i - 1] = val;
i -= 1;
}
// fix up stack pointer
*sp = 0;
return (1ull << (altered_sp + 1)) - 1;
} else {
stack[*sp] += 1;
return 1ull;
}
}
void Generate(const uint64_t n, const uint64_t k) {
uint32_t *stack = (uint32_t *)calloc(n-k+1, sizeof(uint32_t));
uint32_t sp = 0;
uint64_t ctr = 0;
while (ctr < (1ull << n)) {
// number of k windows the algorithm walks through.
const uint64_t limit = k+1-stack[sp];
//print_stack(stack, n, k);
for (uint64_t cw = limit; cw > 1; --cw) {
// start printing
const uint64_t nr_steps = (1ull << cw) - 1ull;
for (uint64_t i = 0; i < nr_steps; ++i) {
f(ctr++);
}
// skip
const uint64_t nr_skip = update_stack(stack, &sp, n, k);
ctr += nr_skip;
}
f(ctr++);
const uint64_t nr_skip = update_stack(stack, &sp, n, k);
ctr += nr_skip;
}
free(stack);
}
which was kinda hard, but it finally worked. I also added a Benchmark, which shows for a simple function f
which is applied for every valid value, how much the speedup compared to the naive way. For n=20
and k=3
its 150 times faster (depending on f).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以递归地进行。
这是C#中的一个示例(对不起,我现在没有设置C/C ++):
生成(4,2)的输出:
生成(5,1)的输出:
You can do it recursively.
Here's an example in C# (sorry, I am not set up for doing c/c++ right now):
Output for Generate(4, 2):
Output for Generate(5, 1):