我试图找出数组中元素的任何组合是否与特定大小相加。
例如 输入:{尺寸:[1,1,3,5],目标:2}输出:是/否=>在这种情况下是1 + 1 = 2
我能想到的其中一个解决方案更多的是强力解决方案,我将有n ^ 2次尝试找到特定于目标的大小。
即。像这样的东西:
for(i=0; i< array.size(); i++) {
for(j=i+1; j< array.size(); j++) {
if(i+j == goal) {
return true;
}
}
}
这是唯一的方法吗?还有,我的代码是否正确?
通过'组合',我不是指'对'(必须恰好是两个项目),而是一个实际的组合(它可以是从0到所有项目的任何地方)
答案 0 :(得分:4)
这是Knapsack Problem的稍微严格的版本。简而言之,没有最好的&#34;解决它的方法,因为它是NP完全问题。
如果有人找到了解决这个问题的最佳方法,我建议您立即写一篇论文,将其提交给ACM和IEEE,并享受您新发现的财富和名望。
我对这些问题没有任何实际经验,但我确实在大学里玩genetic algorithms,在这类事情上取得了相当大的成功。亲自给我一个机会。
如果您处理的数据集与问题中的数据集一样小,那么您最好只是强制执行它。对于一组5个数字,最多有325个可能的排列,这不会花费太长时间来迭代。如果您在评论中提出了像neuronaut这样的常识优化,那么就会花费更少的时间。
结果是你有一个relevant XKCD。享受。
答案 1 :(得分:0)
经过一番研究后发现,这里描述的问题不是背包问题。背包问题要求进入背包的每件物品都有2个变量(通常是质量和数值),为了解决这个问题,你必须选择合计不超过背包所允许的最大质量的物品组合 该组合必须是具有最大值总和的组合。正是这种要求的配对使得背包问题成为NP完全,因为它意味着计算所有组合以便选择具有最大价值的组合。
但是,这个问题每个项目只有一个变量:大小。因此,它不是NP完全的,并且即使在大输入的情况下也可以非常容易且快速地解决。
private List<Integer> solution = new ArrayList<Integer> ();
private boolean hasGoalSum(List<Integer> list, int goal)
{
// this if statement is the key to making this algorithm fast
// since the algorithm is recursive it ends up eliminating many combinations
// that don't need to be tested
if (list.isEmpty () || goal > sumList(list) || goal < Collections.min (list))
{
return false;
}
// next we remove items from the list that are greater than the goal
// since the can't be used to sum up to the goal
list = rejectIfGreaterThanGoal (list, goal);
if (list.contains (goal))
{
solution.add (goal);
return true;
}
// if we don't have a solution yet we take the biggest item from the list and
// and check if combining it with any of the remaining items will result
// in an answer. If not, we then recursively call with a smaller list a
// new subgoal. If there's still no solution we move to the next biggest
// item in the list and so on until exhausting the list or finding a solution.
while (!list.isEmpty ())
{
int m = Collections.max (list);
list.remove ((Integer) m);
if (list.contains (goal - m))
{
solution.add (m);
solution.add (goal - m);
return true;
}
if (hasGoalSum (list, goal - m))
{
solution.add (m);
return true;
}
}
return false;
}
private int sumList (List<Integer> list)
{
int sum = 0;
for (Integer num : list)
{
sum += num;
}
return sum;
}
private List<Integer> rejectIfGreaterThanGoal (List<Integer> list, int goal)
{
List<Integer> newList = new ArrayList<> ();
for (Integer i : list)
{
if (i <= goal)
newList.add (i);
}
return newList;
}
我在这里包含了类成员变量solution
,因此您可以将其打印出来,以便在返回的布尔值(由OP请求)不够的情况下查看查找解决方案。
我还应该注意到卡通中的问题与这个问题基本相同,因此可以通过相同的算法来解决。只需创建一个列表,其中包含价格等于或小于目标的每个菜肴的数量(例如,列表将包含七个2.15条目,五个2.75条目等),然后将其提供给hasGoalSum
方法以及15.05的目标。有了卡通的问题,看solution
比hasGoalSum
方法的布尔结果更有趣。
如果每个开胃菜分配了一些卡路里,那么卡通的问题就是背包问题(因此也就是NP完全问题),并且对服务员的要求不仅要带来价值15.05美元的开胃菜,还要带来最少卡路里的组合。
答案 2 :(得分:0)
使用背包并使权重[] = valuesOrProfit []
打电话给Algo Integer [] response = KnapsackSolver(weight,valuesOrProfit,finalWeight);
获得解决方案。
这里的finalWeight只不过是你想要匹配的确切总和。!!!
如果您没有约束,只有两个数字应该等于问题中提到的最终权重(finalWeight),这将有效。!!!
祝你好运!!!