我知道它的晚来回答我会很乐意,但我想我已经找到了这个问题的简单解决方案。我们使用回溯法列举按照字典顺序排列的S
的子集,并检查到目前为止生成的子集的sum
。
当sum
超过k
时,有趣的部分是:我们需要检查生成的subset
是否是先前报告的项目的正确子集。
一个解决方案是保留所有报告的子集并检查包含,但这是浪费。
相反,我们计算k
和sum
之间的差异。如果在S
这样e not in subset
和e <= (k - sum)
元素e
,那么我们所产生的一组是先前报道的子集的真子集,我们可以跳过它。
这里是普通的老式C++的完整的工作程序,充分展示了主意:
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
typedef std::set<int> Set;
typedef std::vector<int> SubSet;
bool seen_before(const Set &universe, const SubSet &subset, int diff) {
Set::const_iterator i = std::mismatch(universe.begin(), universe.end(),
subset.begin()).first;
return i != universe.end() && *i <= diff;
}
void process(const SubSet &subset) {
if (subset.empty()) {
std::cout << "{}\n";
return;
}
std::cout << "{" << subset.front();
for (SubSet::const_iterator i = subset.begin() + 1, e = subset.end();
i != e; ++i) {
std::cout << ", " << *i;
}
std::cout << "}\n";
}
void generate_max_subsets_rec(const Set &universe, SubSet &subset,
long sum, long k) {
Set::const_iterator i = subset.empty()
? universe.begin()
: universe.upper_bound(subset.back()),
e = universe.end();
if (i == e) {
if (!seen_before(universe, subset, k - sum))
process(subset);
return;
}
for (; i != e; ++i) {
long new_sum = sum + *i;
if (new_sum > k) {
if (!seen_before(universe, subset, int(k - sum)))
process(subset);
return;
} else {
subset.push_back(*i);
if (new_sum == k)
process(subset);
else
generate_max_subsets_rec(universe, subset, new_sum, k);
subset.pop_back();
}
}
}
void generate_max_subsets(const Set &universe, long k) {
SubSet subset;
subset.reserve(universe.size());
generate_max_subsets_rec(universe, subset, 0, k);
}
int main() {
int items[] = {1, 2, 3, 4, 5};
Set u(items, items + (sizeof items/sizeof items[0]));
generate_max_subsets(u, 7);
return 0;
}
输出是字典顺序所有最大的子集,每行一个:
{1, 2, 3}
{1, 2, 4}
{1, 5}
{2, 5}
{3, 4}
可以'S'包含重复的值?例如'S = {1,2,3,4,5}'? – Seph 2012-03-11 10:01:37
@Seph,不,它是'set' =没有重复 – dantuch 2012-03-11 10:14:21