如何从给定的向量中检测所有可能的子集?

时间:2014-10-11 16:54:02

标签: c++ data-structures

我正在编写一个函数,该函数应检测主矢量中的所有可能子集并将它们推送到另一个矢量。子集中的元素在被推入新向量(s1)之前也相互添加。

目前我的代码所做的是以下内容.. 例如,我们说myvec = {1,2,3},然后v1 = {1,3,6,2,5,3}。它只是连续数字的总和。但是,我还希望它总结像1 & 3之类的组合,它们会向向量v1添加4。目前,我无法以我能实现的方式修改算法。任何帮助将不胜感激!

for (k=0; k<myvec.size(); k++) {
        total = 0;
        for (m=k; m<int_vec.size(); m++) {          
            total += myvec[m];
            v1.push_back(total);
        }
    }

1 个答案:

答案 0 :(得分:1)

考虑给定(有序)集的幂集的一种方法是将其元素(子集)视为位向量,其中 n -th位设置为1,如果和仅当为该子集选择了 n -th元素集时。

因此,在您的示例中,您将拥有一个可以表示为无符号整数的3位向量。你将“位向量”从0(空集)向上计数到7(整个集)。然后,在每次迭代中,选择要为其设置相应位的元素。

可以很容易看出,功率集快速爆炸,这使得对于具有十几个元素的任何集合明确计算是不切实际的。

将这些想法转化为C ++,我们得到以下结论。

#include <climits>      // CHAR_BIT
#include <iostream>     // std::cout, std::endl
#include <stdexcept>    // std::invalid_argument
#include <type_traits>  // std::is_arithmetic
#include <vector>       // std::vector

template<typename T>
std::vector<T>
get_subset_sums(const std::vector<T>& elements)
{
  static_assert(std::is_arithmetic<T>::value, "T must be arithmetic");
  if (elements.size() > CHAR_BIT * sizeof(unsigned long))
    throw std::invalid_argument {"too many elements"};
  const std::size_t power_size {1UL << elements.size()};
  std::vector<T> subset_sums {};
  subset_sums.reserve(power_size);
  for (unsigned long mask = 0UL; mask < power_size; ++mask)
    {
      T sum {};
      for (std::size_t i = 0; i < elements.size(); ++i)
        {
          if (mask & (1UL << i))
            sum += elements.at(i);
        }
      subset_sums.push_back(sum);
    }
  return subset_sums;
}


int
main()
{
  std::vector<int> elements {1, 2, 3};
  for (const int sum : get_subset_sums(elements))
    std::cout << sum << std::endl;
  return 0;
}

您可能希望将std::unordered_set用于子集和而不是std::vector,以便为重复项保存空间(以及冗余的进一步处理)。

程序输出数字0(空总和),1(= 1),2(= 2),3(= 1 + 2),3(= 3),4(= 1 + 3),5 (= 2 + 3)和6(= 1 + 2 + 3)。我们可以使这更具视觉效果。

 mask        mask
 (decimal)   (binary)    subset      sum
–––––––––––––––––––––––––––––––––––––––––––––––––
 0           000         {}          0
 1           001         {1}         1
 2           010         {2}         2
 3           011         {1, 2}      3
 4           100         {3}         3
 5           101         {1, 3}      4
 6           110         {2, 3}      5
 7           111         {1, 2, 3}   6