[英]Given a set of integers L and an integer K, select a minimal subset S of L such that SUM(S) >= K
Problem was a little too long for the title, so here is the exact definition: 问题对标题来说太长了,所以这里是确切的定义:
Input 输入项
Set of integers, L 整数集L
Integer, K 整数,K
Output 输出量
A subset of L such that: L的子集,使得:
eg 例如
Input 输入项
L = { 4, 2, 3, 1 } L = {4,2,3,1}
K = 5 K = 5
The first two criteria would yield {4, 2}, {4, 3}, {4, 1}, and {2, 3}. 前两个条件将产生{4,2},{4,3},{4,1}和{2,3}。 We would prefer {2, 3} since its maximum value (3) is least of those.
我们更喜欢{2,3},因为它的最大值(3)是其中的最小值。
Return null or throw and exception if there is no subset that meets the criteria. 如果没有满足条件的子集,则返回null或throw和exception。
I'm a little worried that this problem is too related to the subset-sum problem and might be NP-complete. 我有点担心此问题与子集和问题过于相关,并且可能是NP完全的。
A solution might be the following: 解决方案可能是以下几种:
(1) Sort L to get l_1, l_2, ..., l_n
, with l_1 > l_2 > ... > l_n
. (1)排序L以获得
l_1, l_2, ..., l_n
,其中l_1 > l_2 > ... > l_n
。
(2) For k=1,2,...,n
, check whether (l_1+...+l_k) >= K
, stop for the smallest k. (2)对于
k=1,2,...,n
,检查(l_1+...+l_k) >= K
停止最小的k。
Now you have the minimal number of elements required to meet the first criteria, and an example set {l_1,...,l_k}.
现在,您具有满足第一个条件所需的最少元素数,并具有示例集
{l_1,...,l_k}.
(3) Now we have to find a set with k elements that satisfies the rest. (3)现在我们必须找到一个包含k个元素的集合,该集合可以满足其余条件。 You could eg start by summing up
您可以例如从总结开始
l_n + l_(n-1) + ... + l_(n-k), then
l_(n+1) + l_n + ... + l_(n-k+1), then
l_(n+2) + l_n + ... + l_(n-k+2), ...
and stop whenever one of these sums exceeds or is equal to K. 当这些总和之一超过或等于K时停止。
(1) can be done in O(n*log(n))
time, (2) can be done in O(n)
time. (1)可以在
O(n*log(n))
时间完成,(2)可以在O(n)
时间完成。 (3) can be done in O(n*k) = O(n^2)
time. (3)可以在
O(n*k) = O(n^2)
时间内完成。 However, this can be improved by using a "telescope sum": 但是,可以通过使用“望远镜总和”来改善此问题:
x := l_n + l_(n-1) + ... + l_(nk)
. x := l_n + l_(n-1) + ... + l_(nk)
。 x < K
, then compute x := x - l_n + l_(n-k+1)
x < K
,则计算x := x - l_n + l_(n-k+1)
x < K
, then compute x := x - l_(n-1) + l_(n-k+2)
etc. x < K
,则计算x := x - l_(n-1) + l_(n-k+2)
等 So (3) can be done in O(n)
, as it seems. 因此,看起来(3)可以在
O(n)
完成。
So in total, O(n*log(n))
seems possible for this task. 因此,总的来说,
O(n*log(n))
似乎可以完成此任务。
It seems pretty easy. 看起来很容易。 Sort
L
and find the first n
elements of L
that add up to K
. 排序
L
并找到第一n
的元素L
加起来K
。 That's it. 而已。 Finding any elements beyond the
nth
element is not any better, though you might be able to trim off the first few elements. 找到
nth
元素之外的任何元素都不会更好,尽管您可以删除前几个元素。 If SUM(L)
is less than K
, then return null or throw an exception. 如果
SUM(L)
小于K
,则返回null或引发异常。
Finding the size of the subset is trivial, you can sort the values in reverse order and then find the first partial sum which is greater than or equal to K. This is bounded by the sorting time, which is O(n log n). 查找子集的大小是微不足道的,您可以按相反的顺序对值进行排序,然后找到大于或等于K的第一个部分和。这受排序时间的限制,即O(n log n)。
In your "greater than or equal to" variant of the subset sum problem, once you find a solution with sum S, you still need to ask "does there exist a subset of length n which has a sum between K and S?" 在子集总和问题的“大于或等于”变体中,一旦找到了总和为S的解决方案,您仍然需要问“是否存在长度为n的子集,其总和介于K和S之间?” Applying this repeatedly will eventually yield the question "does there exist a subset of length n which has a sum of K?"
反复应用这一点将最终产生一个问题“是否存在长度为n的子集,其总和为K?” You can't say that your solution is optimal without answering this question.
您不能不回答这个问题就说您的解决方案是最佳的。
The fixed-size subset sum decision problem is NP-complete (since there are only n possible lengths and if this sub-problem was not NP-complete, neither would be the subset sum decision problem). 固定大小的子集和决策问题是NP完全的(因为只有n个可能的长度,并且如果此子问题不是NP完全的,那么子集和决策问题也不是)。
Here is an algorythm: 这是一个算法:
Recursion is as follows in Java 递归在Java中如下
private List<Integer> numbers = Arrays.asList(5, 4, 3, 2, 1);
private List<List<Integer>> combinations = new ArrayList<>();
public void selectCombinations(int position, List<Integer> currentCombination) {
if (position >= numbers.size()) {
return;
}
//next number
selectCombination(position + 1, currentCombination);
List<Integer> newCombination = new ArrayList<>(currentCombination);
newCombination.add(numbers.get(position));
int sum = ...;//sum of copy
if (sum >= K) {
combinations.add(newCombination);
} else {
selectCombination(position + 1, newCombination);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.