找出数组中元素的任何组合是否与特定大小相加

时间:2015-05-15 20:42:30

标签: java

我试图找出数组中元素的任何组合是否与特定大小相加。

例如 输入:{尺寸:[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到所有项目的任何地方)

3 个答案:

答案 0 :(得分:4)

这是Knapsack Problem的稍微严格的版本。简而言之,没有最好的&#34;解决它的方法,因为它是NP完全问题。

如果有人找到了解决这个问题的最佳方法,我建议您立即写一篇论文,将其提交给ACM和IEEE,并享受您新发现的财富和名望。

我对这些问题没有任何实际经验,但我确实在大学里玩genetic algorithms,在这类事情上取得了相当大的成功。亲自给我一个机会。

如果您处理的数据集与问题中的数据集一样小,那么您最好只是强制执行它。对于一组5个数字,最多有325个可能的排列,这不会花费太长时间来迭代。如果您在评论中提出了像neuronaut这样的常识优化,那么就会花费更少的时间。

结果是你有一个relevant XKCD。享受。

enter image description here

答案 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的目标。有了卡通的问题,看solutionhasGoalSum方法的布尔结果更有趣。

如果每个开胃菜分配了一些卡路里,那么卡通的问题就是背包问题(因此也就是NP完全问题),并且对服务员的要求不仅要带来价值15.05美元的开胃菜,还要带来最少卡路里的组合。

答案 2 :(得分:0)

使用背包并使权重[] = valuesOrProfit []

打电话给Algo Integer [] response = KnapsackSolver(weight,valuesOrProfit,finalWeight);

获得解决方案。

这里的finalWeight只不过是你想要匹配的确切总和。!!!

如果您没有约束,只有两个数字应该等于问题中提到的最终权重(finalWeight),这将有效。!!!

祝你好运!!!