我正在编写一个函数,该函数应检测主矢量中的所有可能子集并将它们推送到另一个矢量。子集中的元素在被推入新向量(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);
}
}
答案 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