我正在尝试n-th在电源集中找到该装置。通过n-th我的意思是幂是按以下顺序产生的-首先由大小,然后,按字典-等,该套中的幂指数[a, b, c]为:
n-th
[a, b, c]
0 - [] 1 - [a] 2 - [b] 3 - [c] 4 - [a, b] 5 - [a, c] 6 - [b, c] 7 - [a, b, c]
在寻找解决方案时,我所能找到的只是一种返回元素列表的第n个排列的算法-。
内容 :
我正在尝试检索V元素向量的整个功率集,但我一次只需要设置一组。
V
要求 :
n-th set
我没有该函数的封闭形式,但是我有一个有点黑客的非循环next_combination函数,如果有帮助,欢迎您。假定您可以将位掩码适合某种整数类型,考虑到64个元素集有2 64种可能性,这可能不是一个不合理的假设。
next_combination
正如评论所言,我发现“字典顺序”的定义有点奇怪,因为我会说字典顺序为: [], [a], [ab], [abc], [ac], [b], [bc], [c]。但是在此之前,我必须先进行“按大小排序,然后按字典顺序”枚举。
[], [a], [ab], [abc], [ac], [b], [bc], [c]
// Generate bitmaps representing all subsets of a set of k elements, // in order first by (ascending) subset size, and then lexicographically. // The elements correspond to the bits in increasing magnitude (so the // first element in lexicographic order corresponds to the 2^0 bit.) // // This function generates and returns the next bit-pattern, in circular order // (so that if the iteration is finished, it returns 0). // template<typename UnsignedInteger> UnsignedInteger next_combination(UnsignedInteger comb, UnsignedInteger mask) { UnsignedInteger last_one = comb & -comb; UnsignedInteger last_zero = (comb + last_one) &~ comb & mask; if (last_zero) return comb + last_one + (last_zero / (last_one * 2)) - 1; else if (last_one > 1) return mask / (last_one / 2); else return ~comb & 1; }
第5行正在做(扩展的)正则表达式替换的位hacking行为,该替换发现01字符串中的最后一个,将其翻转到最后,10然后将所有随后的1s一直移到右边。
01
10
1
s/01(1*)(0*)$/10\2\1/
第6行执行此操作(仅在前一个操作失败的情况下)再添加一个1并将1s一直向右移动:
s/(1*)0(0*)/\21\1/
我不知道该解释是有用的还是不利的:)
这是一个快速且肮脏的驱动程序(命令行参数是集合的大小,默认为5,最大为无符号long的位数):
#include <iostream> template<typename UnsignedInteger> std::ostream& show(std::ostream& out, UnsignedInteger comb) { out << '['; char a = 'a'; for (UnsignedInteger i = 1; comb; i *= 2, ++a) { if (i & comb) { out << a; comb -= i; } } return out << ']'; } int main(int argc, char** argv) { unsigned int n = 5; if (argc > 1) n = atoi(argv[1]); unsigned long mask = (1UL << n) - 1; unsigned long comb = 0; do { show(std::cout, comb) << std::endl; comb = next_combination(comb, mask); } while (comb); return 0; }
很难相信,考虑到枚举的大小,此函数可能对超过64个元素的集合有用,但枚举某些有限的部分(例如三个元素的所有子集)可能很有用。在这种情况下,仅当修饰词适合单个单词时,比特黑客才真正有用。幸运的是,这很容易测试。您只需要对位集中的最后一个单词进行上述计算,直到测试last_zero为零为止。(在这种情况下,您不需要bitand mask,实际上您可能希望选择其他方式来指定集合大小。)如果last_zero结果为零(实际上很少见),则需要执行以其他方式进行转换,但原理相同:找到第一个0在1(当心0在单词的末尾和下一个单词1的开始处时要当心);将更01改为10,找出1需要移动多少个,然后将它们移动到末尾。
last_zero
mask
0