我想知道是否存在解决此问题的算法。它有点类似背包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},依此类推。有没有一种有效的方法来做到这一点?让我知道
答案 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)。