给出最小和大于或等于给定数字的子集

时间:2017-05-19 23:22:21

标签: algorithm combinatorics knapsack-problem subset-sum

我有一组(多)正数,例如。 {71.28, 82.62, 148.77, 85.05, 50.76, 103.41}

我想找到一个子集,它给出最大和大于或等于给定数字

EG。如果最小值为270,则结果为{148.77, 71.28, 50.76},其总和为270.81

注意:我认为解决方案可能与背包更相似,而不是子集和。

1 个答案:

答案 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;
}