【问题标题】:How to generate the combination of all valid bit changes towards a binary integer?如何生成所有有效位变化向二进制整数的组合?
【发布时间】:2013-03-07 07:46:18
【问题描述】:

将 2 位或更少的更改定义为 32 位整数被认为是“有效的”。
为简化起见,让我们以 4 位二进制为例。
0000 -> 1000 有效
0000 -> 1100 有效
0000 -> 1001 有效
0000 -> 1101 无效

所以实际上这意味着有 C(32, 2) * 2^2 种可能的组合

我想知道如何编写像vector<int> foo(int numberToBeChanged, int n) 这样的函数,它接受一个数字n(允许的位更改数)并返回所有可能组合的集合?谢谢。

【问题讨论】:

  • 您真的需要可能的更改列表(我想是从 0x00000000 开始)还是检查给定数字是否是允许更改的函数(从 0x00000000 开始)?
  • 如果您只需要一个函数来计算 Hamming distance of two binary strings 并且您使用的是现代 X86 处理器,您可能需要查看 POPCNT 指令(与 xor 结合)
  • 关于可能组合的数量,实际上它不是您所指出的 C(32, 2) * 4 ,因为您也计算了重复项。组合的实数为 1 + 32 + C(32, 2),3 部分中的每一个分别表示无变化、1 位变化和 2 位变化的组合。
  • @AndreHolzner 一个列表,检查相当容易

标签: algorithm bit-manipulation


【解决方案1】:

这样就可以了:

#include <iostream>
#include <vector>
using namespace std;

vector<unsigned int> foo(unsigned int n)
{
    vector<unsigned int> ans;

    // One of the combinations is not to change anything, i.e. number itself
    ans.push_back(n);

    for(unsigned int i = 0; i < 32; i++) {
        // Combinations with only one bit changed
        ans.push_back(n ^ (1 << i));
        for(unsigned int j = 0; j < i; j++) {
            // Combinations with two bits changed
            ans.push_back(n ^ (1 << i) ^ (1 << j));
        }
    }
    return ans;
}

int main()
{
    vector<unsigned int> v = foo(0);
    for(unsigned int i = 0; i < v.size(); i++) {
        cout << v[i] << endl;
    }
    return 0;
}

附: 这里是根据描述变化修改的代码:

#include <iostream>
#include <vector>
using namespace std;

/*
    start denotes bit number from which we should start loop, i.e. we can't
    modify any bits before that bit to avoid duplicates (we are modifying bits
    with order from lowest to highest, so if we have modified some bit, next bit
    to modify should be a higher one.
*/
void foo(vector<unsigned int>& ans, unsigned int number, int n, unsigned int start)
{
    // As we reached to current number someway then it is one of the combinations
    ans.push_back(number);
    if(n < 1) {
        // No more changes allowed, go back
        return;
    }

    // Try change one bit
    for(unsigned int i = start; i < 32; i++) {
        foo(ans, number ^ (1 << i), n - 1, i + 1);
    }
}

int main()
{
    vector<unsigned int> v;
    unsigned int startingNumber = 0;
    int changesAllowed = 2;
    foo(v, startingNumber, changesAllowed, 0);
    for(unsigned int i = 0; i < v.size(); i++) {
        cout << v[i] << endl;
    }
    return 0;
}

【讨论】:

  • 嗨 aram90 感谢您输入答案。然而 n 实际上表示允许的位更改数。检查我刚才的编辑。我知道这个论点具有误导性。对此感到抱歉。
  • 是的,我后来才知道该怎么做。我没有使用您的 number 参数,而是添加了一行来检查是否设置了位。如果是则中断。还是谢谢!
【解决方案2】:

如果您只想更改数字 N 中的两位,可以使用:

for (size_t i = 0; i < sizeof(int); ++i) {
    int one = N ^ (1<<i);
    for (size_t j = 0; j < i; ++j)
        vec.push(one ^ (1<<j));
    vec.push(one);
}
vec.push(N);

对于任何另一个 n:生成一个数字列表,其中设置了 n、(n-1)、... 0 位,并将你的 N 与所有这些位进行异或。有很多已回答的问题,如何生成这样的列表。 事实上,对于大 n,有 O(2^(sizeof(int))) 个可能的数字。如果我只想迭代它们,我更喜欢使用生成器,而不是完整列表。

【讨论】:

    猜你喜欢
    • 2016-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-22
    相关资源
    最近更新 更多