我有一组(多)正数,例如。 {71.28, 82.62, 148.77, 85.05, 50.76, 103.41}
。
我想找到一个子集,它给出最大和大于或等于给定数字。
EG。如果最小值为270
,则结果为{148.77, 71.28, 50.76}
,其总和为270.81
。
注意:我认为解决方案可能与背包更相似,而不是子集和。
答案 0 :(得分:3)
子集求和问题和背包问题在他们的解决方案中非常相似,您可以使用其中任何一个来解决问题。然而,背包问题具有动态编程解决方案,其更有利于解决该特定问题。看一下这个链接,看看我的出发点: http://www.geeksforgeeks.org/dynamic-programming-set-10-0-1-knapsack-problem/ 上述解决方案递归地迭代集合的每个排列,从起始和减去每个集合元素的值,直到减法将导致和值为负。这表示检查的子集的值大于指定的输入数,或者在您的示例中,子集的附加值大于270的情况。在DP背包解决方案中,我们只是跳过该set元素并移动到下一个。在我的解决方案中,我检查该解决方案的值是否是迄今为止看到的最大值,大于输入数字(在您的示例中为270)。如果是,我更新函数的两个参数。一个参数是跟踪的总和与我们正在检查的集合中的元素之间的差异。该参数为我们提供了子集的附加值与输入数的接近程度,而无需计算附加值或记住原始输入数。另一个参数是当前集合,其附加值最接近但大于我们的输入数字。在C ++中,set保存在std :: vector引用中(它也可以使用set或multiset)。如果没有设置添加到大于输入数字的值,则此算法返回空向量。
#include<iostream>
#include<vector>
#include<climits>
template<typename T>
void print(std::vector<T> v)
{
for(auto i : v)
std::cout<<i<<" ";
std::cout<<std::endl;
}
template<typename T>
T closestVal(T sum, std::vector<T>& set, size_t n, std::vector<T> curSet, int& minSum, std::vector<T>& ret)
{
if(n == 0 || sum == 0)
return 0;
if(set[n-1] >= sum) {
if(sum-set[n-1] > minSum) {
minSum = sum-set[n-1];
std::vector<T> newSet = curSet;
newSet.push_back(set[n-1]);
ret = newSet;
}
return closestVal(sum, set, n-1, curSet, minSum, ret);
}
else {
std::vector<T> newSet = curSet;
newSet.push_back(set[n-1]);
return std::max(
set[n-1] + closestVal(sum-set[n-1],set,n-1, newSet, minSum, ret),
closestVal(sum, set, n-1, curSet, minSum, ret)
);
}
}
int main()
{
std::vector<double> ms{71.28, 82.62,148.77, 85.05, 50.76, 103.41};
std::vector<double> ret; //ret is empty, will be filled with the return value
int i = INT_MIN; //i is instantiated to the smallest possible number
closestVal(270.81, ms, ms.size(), {}, i, ret);
print(ret);
return 0;
}