Поскольку вы упомянули C / C ++ / Fortran, я попытался сохранить этот язык относительно независимым / легко переносимым , но также добавил быстрее встроенные альтернативы где это применимо.
Все целые числа имеют одинаковое количество установленных битов N
Тогда мы также можем сказать, все допустимые целые числа будут перестановками N установить биты.
Сначала мы должны сгенерировать начальную / минимальную перестановку:
uint32_t firstPermutation(uint32_t n){
// Fill the first n bits (on the right)
return (1 << n) -1;
}
Затем мы должны установить конечную / максимальную перестановку - указав «точку остановки»:
uint32_t lastPermutation(uint32_t n){
// Fill the last n bits (on the left)
return (0xFFFFFFFF >> n) ^ 0xFFFFFFFF;
}
Наконец, нам нужен способ получить следующую перестановку.
uint32_t nextPermutation(uint32_t n){
uint32_t t = (n | (n - 1)) + 1;
return t | ((((t & -t) / (n & -n)) >> 1) - 1);
}
// or with builtins:
uint32_t nextPermutation(uint32_t &p){
uint32_t t = (p | (p - 1));
return (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctz(p) + 1));
}
Все целые числа имеют одинаковую сумму битовых индексов K
Предполагая, что это целые числа (32 бита), вы можете использовать эту последовательность ДеБрюйна для быстрого определения индекса первого установленного бита - fsb . Аналогичные последовательности существуют для других типов / битовых чисел, например этот один может быть адаптирован для использования.
Удалив текущий fsb , мы можем применить вышеупомянутую технику к определить индекс следующего fsb и т. д.
int sumIndices(uint32_t n){
const int MultiplyDeBruijnBitPosition[32] = {
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
int sum = 0;
// Get fsb idx
do sum += MultiplyDeBruijnBitPosition[((uint32_t)((n & -n) * 0x077CB531U)) >> 27];
// strip fsb
while (n &= n-1);
return sum;
}
// or with builtin
int sumIndices(uint32_t n){
int sum = 0;
do sum += __builtin_ctz(n);
while (n &= n-1);
return sum;
}
Наконец, мы можем перебирать каждую перестановку, проверяя, соответствует ли сумма всех индексов указанному значению K.
p = firstPermutation(n);
lp = lastPermutation(n);
do {
p = nextPermutation(p);
if (sumIndices(p) == k){
std::cout << "p:" << p << std::endl;
}
} while(p != lp);
Вы можете легко изменить код «обработчика», чтобы сделать что-то подобное, начиная с заданное целое число - используя его значения N и K.
тест встроенного c по сравнению с самореализацией