给定一组有限的排序实数,产生所有可能的子集,其和<= k

时间:2012-03-23 18:17:32

标签: arrays algorithm

我想知道是否存在解决此问题的算法。它有点类似背包0-1问题,或功率设置问题,但它是不同的。

给定一组有限的排序实数,我们需要生成其总和<= k的所有可能子集。这里k是真实的,排序的实数都是正数。例如,数组= {1.48,2.21 3.07,4.35,4.46}和k = 5.94输出为:{4.46},{4.46,1.48},{4.35},{4.35,1.48},{3.07},{3.07,2.21 },{2.21},{2,21,1:48}和{1.48}。

要解决的一种方法是简单地从最高数量{4.46}进行遍历,看看你可以在篮子中包含多少,然后继续下一个最低数字{4.35},依此类推。有没有一种有效的方法来做到这一点?让我知道

2 个答案:

答案 0 :(得分:4)

贪婪算法绝对可以工作。为了利用输入排序的事实,可以使用二进制搜索。

基本思想是:首先通过二分查找搜索数组中小于K的最大数字,将结果元素推送到堆栈,然后递归搜索结束于该元素的子数组,得到总和K - 该元素的价值。完成此操作后,在子数组中搜索总和K,以涵盖未选择该元素的情况。

示例代码:

void boundedSumSubarray(float * arr, int size, float K, stack S) {
    int pos=binarySearch(arr,size,K);
    if (pos>=0) {
        pushStack(S,arr[pos]);
        boundedSumSubarray(arr,pos-1,K-arr[pos],S);
        popStack(S);
        boundedSumSubarray(arr,pos-1,K,S);
    } else
        printStack(S);
}

答案 1 :(得分:1)

您需要“生成”所有子集,而不是“计算”所有子集。这使得工作变得更加容易:)

设F(x,y,k)为x [1:k]的子集,其和小于y。

F(x,y,k+1) = F(x,y,k) \union { for each set g in F(x,y-x[k+1], k): g \union {k+1} }

使用上面的递归来生成所有这些情况。

请注意,执行F(x,y-x[k+1], k)时不必实际重新计算子集集。只需将列表保存在树形结构中即可。

如果您期望的子集数是m,则此算法为O(nm)。