二进制位的一个问题。
前几天在做TC时遇到的,题意大概是这样,给你一个数组,取数组里面的数字进行加和运算。然后求最小的不能利用加和得到的正数。
Attention:每次加和时,每个数字最多能用一次。
Sample:
如果数组A为[1,2,3]
那么所有的可能的加和为:1, 2, 3, 4, 5, 6
所以最小的不能得到的正数是7
(数据规模是数组最多为20个元素)
当时我用的方法是暴力DFS, 最多有 2^20中情况。然后把所有的情况扔到数组中,扫描一遍即可。
看题解的时候,发现题解虽然也是用的暴力,但是是用的bitmask,所以学习了一种新方法。
先把题解的代码贴出:
static const int MAX = 100000 * 20 + 1;
bool poss[MAX];
int MinNumber(vector<int> S)
{
fill(poss, poss + MAX, false);
int n = S.size();
// All subsets:
for (int mask = 0; mask < (1<<n); mask++) {
int sum = 0;
for (int i = 0; i < S.size(); i++) {
if (mask & (1<<i)) {
sum += S[i];
}
}
poss[sum] = true;
}
int x = 1;
while (poss[x]) {
x++;
}
return x;
}
n为数组中元素的个数。所以一共有2^n中状态。
所以开始 1<<n, 表示这2^n种状态。
然后,mask从0到1<<n,表示对数组中元素的取舍状态。
比如mask为3的时候,那么以为着其二进制数位11.表示取数组中的第0个和第1个元素相加。
mask为5则意味着101,表示取数组中的第0个和第2元素相加,而忽略其他元素。
这样就能够获得所有状态的加和。
后面扫描一遍即可了。