C++ 根据设置的位数计算组合

C++ 根据设置的位数计算组合,c++,c,algorithm,C++,C,Algorithm,我需要计算在某个时间选择的n个事物的所有可能组合,其中0迭代某些数量的项目的所有组合会被quant_dev很好地覆盖。实现常规算法以生成组合,但也保留一个额外的数组,在其中存储根据1位集排序的数字。然后,对于生成的每个组合,将数字替换为数组中相应位置的数字减去1,如我所述。下面是一个简单的方法函数,用于计算数字表示中设置的位数: // Counts how many bits are set in the representation of the input number n int numO

我需要计算在某个时间选择的n个事物的所有可能组合,其中0迭代某些数量的项目的所有组合会被quant_dev很好地覆盖。

实现常规算法以生成组合,但也保留一个额外的数组,在其中存储根据1位集排序的数字。然后,对于生成的每个组合,将数字替换为数组中相应位置的数字减去1,如我所述。

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

// 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;
    }
}

您可以递归地执行此操作:

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);
    }
}
这些数字不能保证按数字顺序排列。

这很容易。 有两种情况:

1) 最后1位之前有0位: 00011001001->00011001010

你应该把它移到左边

2) 有一个1位链: 000110111100->000111000111

然后,您应该将最后1位移到左侧(链之前)最近的0位,并将该链的所有其他位移到右侧


通过这种方式,您将以递增的顺序获得所需的所有数字。

我在您的“问题”中没有看到任何问题。#我在您的“问题”中看到许多问题。它是哪一个?@AkashdeepSaluja…“设置位数”在一个数字中被称为its。这类似于如何有效地根据1位数集对数字进行排序吗?事实上,你不需要有效地进行排序-你只需要执行一次,然后生成所有组合。事实是,即使是你能想到的最糟糕的实现也不会有什么不同。与其写
pow(2,n)
,不如写
1和
itoa
应该使用
2
的基数,而不是
0
。另外,
itoa
不接受两个迭代器,但第一个参数是数字,第二个是目标C字符串。我不明白你怎么能把它和向量一起使用。你的意思是用零填充向量吗?@leemes:那不是
itoa
,那是
iota
@leemes:不必抱歉,你的评论帮我发现
std::iota
不在C++98;-)我不确定我是否遗漏了什么,但这个数字链必须从某个地方开始(假定为0),但现在没有规则我应该如何处理0,因为没有设置位。显然,接下来是1。然后我应用第一个规则,直到我有0b100…0,但是我该怎么做呢?同样,对于获取下一个数字(在本例中为3)缺少一个规则。您从0b00000…0011…111开始,并且始终具有r 1位。如果您得到0b11…111000.000,这是最后一个数字。你所要做的就是向前移动最后一个1位,向后移动这个链中的另一个1位,仍然有R1位。
#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;
    }
}
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