整数的真后代数求解算法咨询
我明白你卡在这个真后代数的生成问题上了——其实核心是抓住二进制子集的本质,用位运算就能高效解决,完全不用逐个遍历小于原数的所有数。让我一步步给你讲清楚:
先明确真后代数的等价定义
根据你给出的数学定义,真后代数h'可以等价为:
h'是原数h的二进制子集:也就是h'的每一位1都对应h的某一位1(用位运算表示就是(h' & h) == h');h' < h(排除原数本身)且h' != 0(保证至少有一个共同的1位)。
核心技巧:枚举二进制子集
最高效的方法是利用位运算直接生成h的所有非空真子集,经典的技巧是用current = (current - 1) & h来依次遍历所有子集。这个表达式的原理是:
- 每次
current - 1会把最右边的1变成0,后面的0全变成1; - 和
h做按位与,会把那些超出h范围的1(也就是h中为0的位)清零,从而得到h的下一个合法子集。
我们只需要跳过初始的h本身,以及最后得到的0,剩下的就是所有真后代数。
C语言实现代码(直接输出版本)
这个版本简单直接,适合快速验证结果:
#include <stdio.h> void print_proper_descendants(int h) { if (h == 0) { printf("No proper descendants (input is 0)\n"); return; } printf("Proper descendants of %d (binary: %d):\n", h, h); int current = h; // 枚举所有子集,跳过原数和0 while ((current = (current - 1) & h) != 0) { printf("%d (binary: %d)\n", current, current); } } int main() { print_proper_descendants(21); // 测试你给出的例子 return 0; }
运行后输出的结果正好和你给出的一致:
Proper descendants of 21 (binary: 10101): 20 (binary: 10100) 17 (binary: 10001) 16 (binary: 10000) 5 (binary: 101) 4 (binary: 100) 1 (binary: 1)
C语言实现代码(收集到数组版本)
如果需要把结果存起来供后续处理,可以用这个版本:
#include <stdio.h> #include <stdlib.h> #include <stdint.h> // 计算二进制中1的个数,用来确定数组大小 int count_set_bits(uint32_t h) { int count = 0; while (h) { count++; h &= h - 1; // 清除最右边的1 } return count; } uint32_t* get_proper_descendants(uint32_t h, int* out_count) { if (h == 0) { *out_count = 0; return NULL; } int bit_count = count_set_bits(h); int total = (1 << bit_count) - 2; // 非空真子集数量:2^k - 2 uint32_t* result = malloc(total * sizeof(uint32_t)); if (!result) { *out_count = 0; return NULL; } int idx = 0; uint32_t current = h; while ((current = (current - 1) & h) != 0) { result[idx++] = current; } *out_count = idx; return result; } int main() { uint32_t h = 21; int count; uint32_t* descendants = get_proper_descendants(h, &count); printf("Proper descendants of %u:\n", h); for (int i = 0; i < count; i++) { printf("%u ", descendants[i]); } printf("\n"); free(descendants); // 记得释放内存 return 0; }
Python版本(供参考)
如果用Python实现,思路完全一致,代码更简洁:
def generate_proper_descendants(h): if h == 0: return [] descendants = [] current = h while (current := (current - 1) & h) != 0: descendants.append(current) return descendants print(generate_proper_descendants(21)) # 输出 [20, 17, 16, 5, 4, 1]
为什么这个方法高效?
这个方法的时间复杂度是O(2^k),其中k是原数h二进制中1的个数,这已经是最优的了——因为真后代数的总数就是2^k - 2,我们直接生成每个结果,没有多余的计算。相比遍历所有小于h的数(时间复杂度O(h)),这个方法在h很大但1的个数很少时,效率提升非常明显。
内容的提问来源于stack exchange,提问作者Quentin
相关产品推荐
相关产品推荐

