问题
假设我们有一组 N 实数 A = {x_1,x_2,...,x_N} 。
目标是将此集合划分为 A_1,A_2,...,A_L 子集,其限制为 sum(A_i)< = T 和最小化这个词:
成本:=总和(abs(sum(A_i) - T))
其中 sum(A_i)表示 A_i 中的数字总和, T 是给定的阈值。
我正在寻找一种非进化的最优算法。
更新: x_i 是真正的正数且不大于 T ( 0< x_i< = T )。
更新2:修复了费用功能。
很好的尝试,贪心算法!
一个简单的想法是使用Greedy方法来解决问题。这是一个伪代码:
1. create subset A_1 and set i=1.
2. remove the largest number x from A.
3. If sum(A_i) + x <= T
* put x into A_i
4. Else
* create a new subset A_i+1,
* put x into A_i+1
* set i=i+1
5. If A is non-empty
* goto step 2.
6. Else
* return all created A_i s
问题是这个解决方案不是最优的。例如,有些情况下最好不要在第一个子集 A_1 中放入两个最大的数字 x1 和 x2 ,即使他们没有超过 T ,因为没有其他* x_i *可用于添加到该集合并使其总和更接近 T 。另一方面,如果我们将 x1 和 x2 放在单独的集合中,则可以找到更好的解决方案(具有较小成本的解决方案值)。
可能的解决方案
我曾想过使用Backtracking算法也可以找到最佳解决方案,但我想这个问题的复杂性会很高。
我在维基百科上读过一些文章,如Bin packing problem(NP-hard [叹气......] )和Cutting stock problem,显然我的问题与此标准非常相似问题,但我不确定哪一个符合我的情况。
答案 0 :(得分:2)
<强>更新强> 使用校正的成本函数,请注意,总和(A_i) - T将始终为负,因为A_i <= T。 所以我们的目标是尽量减少
sum(abs(sum(A_i)-T))= sum(T-sum(A_i))= L * T-sum(A)
sum(A)是常数,因此任务是尽量减少使用的箱数。因此,您的问题相当于经典的垃圾箱包装。
要解决此问题,您可以使用像this one这样的bin打包解算器。