根据设置的位数计算组合

时间:2013-01-28 12:42:04

标签: c++ c algorithm

我需要在0 <= r <= n的时间计算所选择的n个事物的所有可能组合。一种方法是生成最多0到2 ^ n-1的数字。但我需要生成这些数字,以便根据该数字中设置的位数对数字进行排序。对于n = 3:

0         // numbers with 0 bits set

1 2 4     // numbers with 1 bits set

3 5 6     // numbers with 2 bits set

7         // numbers with 3 bits set

我需要知道如何生成数字,使它们按比特的递增/递减顺序排序?

5 个答案:

答案 0 :(得分:0)

quant_dev here可以很好地覆盖一些项目的所有组合。

答案 1 :(得分:0)

实现常规算法以生成组合,但还包含一个附加数组,用于存储根据1位集排序的数字。然后,对于生成的每个组合,将数字替换为位于相应位置的数字减去按照我所描述的数组排序的数字。

答案 2 :(得分:0)

这是一个简单的方法函数,用于计算数字表示中设置的位数:

// Counts how many bits are set in the representation of the input number n
int numOfBitsSet(int n)
{
    int cnt = 0;
    while (n != 0)
    {
        cnt += (n & 1);
        n = n >> 1;
    }

    return cnt;
}

以下是如何在(C ++ 11)程序中使用它来实现你想要的:

#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>

using namespace std;

int main()
{
    // For instance...
    int n = 3;

    // Fill up a vector of 2^n entries (0 .. 2^(n - 1))
    vector<int> v(1 << n);
    iota(begin(v), end(v), 0);

    // For each number of bits...
    for (size_t i = 0; i <= n; i++)
    {
        cout << "Numbers with " << i << " bits set: ";

        // Find the first number with i bits set...
        auto it = find_if(begin(v), end(v), [i] (int x) { 
            return (numOfBitsSet(x) == i); 
            });

        while (it != end(v))
        {
            cout << *it << " ";

            // Find the next number with i bits set...
            it = find_if(next(it), end(v), [i] (int x) { 
                return (numOfBitsSet(x) == i); 
                });
        }

        cout << endl;
    }
}

如果C ++ 11不适合您,则必须使用仿函数而不是lambdas,并用手动循环替换std::iota

#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>

using namespace std;

struct bit_count_filter
{
    bit_count_filter(int i) : _i(i) { }
    bool operator () (int x) const { return numOfBitsSet(x) == _i; }
    int _i;
};

int main()
{
    // For instance...
    int n = 3;

    // Fill up a vector of 2^n entries (0 .. 2^(n - 1))
    vector<int> v(1 << n);
    for (size_t i = 0; i < v.size(); i++)
    {
        v[i] = i;
    }

    // For each number of bits...
    for (size_t i = 0; i <= n; i++)
    {
        cout << "Numbers with " << i << " bits set: ";

        // Find the first number with i bits set...
        auto it = find_if(begin(v), end(v), bit_count_filter(i));
        while (it != end(v))
        {
            cout << *it << " ";

            // Find the next number with i bits set...
            it = find_if(next(it), end(v), bit_count_filter(i));
        }

        cout << endl;
    }
}

答案 3 :(得分:0)

你可以递归地做到:

void setnbits(unsigned int cur, int n, int toset, int max)
{
    if(toset == 0)
    {
        printf("%d ", cur >> (n + 32 - max) , n);
        return;
    }
    toset--;
    for(int i = 1 ; i <= n-toset ; i++)
    {
        setnbits((cur >> i) | 0x80000000, n-i, toset , max);
    }
}

可以像:

一样调用
for(int z = 0 ; z < 4 ; z++)
{
    printf("%d bits: ", z);
    setnbits(0, 3, z, 3);
    printf("\n");
}

打印:

0 bits: 0
1 bits: 1 2 4
2 bits: 3 5 6
3 bits: 7

不保证数字按数字顺序排列。

答案 4 :(得分:0)

这很简单。 有两种情况:

1)最后1位之前有0位:    00011100100 1 - &gt; 0001110010的 1 0

你应该把它移到左边

2)有一个1位的链:    00011 01111 00 - &gt; 00011的 1 000的 111

然后你应该将最后的1位移动到左边最近的0位(在链之前),然后将该链的所有其他位移到右边。

你会按顺序获得所有需要的数字。