📜  使用位集的子集总和查询

📅  最后修改于: 2021-05-25 06:44:47             🧑  作者: Mango

给定一个数组arr []和多个查询,在每个查询中,我们必须检查数组中是否存在总和等于给定数字的子集。

例子:

Input : arr[]   = {1, 2, 3};
        query[] = {5, 3, 8}  
Output : Yes, Yes, No
There is a subset with sum 5, subset is {2, 3}
There is a subset with sum 3, subset is {1, 2}
There is no subset with sum 8.

Input : arr[] = {4, 1, 5};
        query[] = {7, 9}
Output : No, Yes
There is no subset with sum 7.
There is a subset with sum 9, subset is {4, 5}

这个想法是在C++中使用位集容器。使用位集,我们可以预先计算O(n)中数组中所有子集和的存在,并仅在O(1)中回答后续查询。

我们基本上使用位数组bit []表示数组中元素的子集总和。 bit []的大小应至少为所有数组元素的总和加1以回答所有查询。如果x是给定数组的子集和,则将bit [x]保持为1,否则返回false。请注意,假定索引从0开始。

For every element arr[i] of input array,
we do following

// bit[x] will be 1 if x is a subset
// sum of arr[], else 0
bit = bit | (bit << arr[i])

这是如何运作的?

Let us consider arr[] = {3, 1, 5}, we need 
to whether a subset sum of x exists or not, 
where 0 ≤ x ≤ Σarri.

We create a bitset bit[10] and reset all the  
bits to 0, i.e., we make it 0000000000.

Set the 0th bit, because a subset sum of 0 
exists in every array.
Now, the bit array is 0000000001

Apply the above technique for all the elements
of the array :
Current bitset = 0000000001

After doing "bit = bit | (bit << 3)", 
bitset becomes    0000001001


After doing "bit | (bit << 1)", 
bitset becomes    0000011011


After doing "bit | (bit << 5)", 
bitset becomes    1101111011    

最后,我们将位数组设置为1101111011,因此,如果bit [x]为1,则x的子集和存在,否则不存在。我们可以清楚地观察到,除了2和7之外,数组中还存在着0到9之间所有数字的子集和。

这是一个C++实现:

// C++ program to answer subset sum queries using bitset
#include 
using namespace std;
  
// Maximum allowed query value
# define MAXSUM 10000
  
// function to check whether a subset sum equal to n
// exists in the array or not.
void processQueries(int query[], int nq, bitset bit)
{
    // One by one process subset sum queries
    for (int i=0; i= MAXSUM)
       {
           cout << "NA, ";
           continue;
       }
  
       // Else if x is a subset sum, then x'th bit
       // must be set
       bit[x]? cout << "Yes, " : cout << "No, ";
    }
}
  
// function to store all the subset sums in bit vector
void preprocess(bitset &bit, int arr[], int n)
{
    // set all the bits to 0
    bit.reset();
  
    // set the 0th bit because subset sum of 0 exists
    bit[0] = 1;
  
    // Process all array elements one by one
    for (int i = 0; i < n; ++i)
  
        // Do OR of following two
        // 1) All previous sums. We keep previous value
        //    of bit.
        // 2) arr[i] added to every previous sum. We
        //    move all previous indexes arr[i] ahead.
        bit |= (bit << arr[i]);
}
  
// Driver program
int main()
{
    int arr[] = {3, 1, 5};
    int query[] = {8, 7};
  
    int n  = sizeof(arr) / sizeof(arr[0]);
    int nq = sizeof(query) / sizeof(query[0]);
  
    // a vector of MAXSUM number of bits
    bitset bit;
  
    preprocess(bit, arr, n);
    processQueries(query, nq,  bit);
  
    return 0;
}

输出:

Yes, No, 

时间复杂度:O(n)用于预先计算,O(1)用于后续查询,其中n是数组中元素的数量。

有关此方法的空间要求,请参阅http://stackoverflow.com/questions/12459563/what-is-the-size-of-bitset-in-c。