【问题标题】:Generating all combinations of list of numbers where the sum of the combination is <= N生成数字列表的所有组合,其中组合的总和 <= N
【发布时间】:2013-03-05 12:22:43
【问题描述】:

我有ArrayList&lt;int&gt;,其中包含可以在组合中使用的所有数字。我想生成这些不同长度的数字(整数个数)的所有可能组合,但所有组合的总和必须最接近 N,但

示例

N = 10
list = {1, 5, 4, 3, 6, 9, 7, 4, 3, 8, 2, 1, 6, 3, 7}

一个组合将是 (1, 5, 4), (3, 6), (9), (7), (4, 3), (8, 2), (1, 6, 3), ( 7)

谁能帮我解决这个问题? 我正在考虑一些递归实现。我在正确的轨道上吗?

编辑

好的,因为我不能完全按照我的意愿解释这个问题:)让我们让它更简单。如何生成 sum

【问题讨论】:

  • 所有子集都由输入中的连续元素组成只是巧合,还是这是一个要求? (例如,1,5,3 也是有效的子集吗?)。另外,请注意,您的要求与您的示例不同。
  • 是的,这是巧合。我只是写这个作为一个例子。 (1, 5, 3) 也是一个有效的子集。重要的是使用所有数字,每个数字只使用一次,子集的总和小于或等于 N,但尽可能接近 N
  • @nikmin 将 (1, 5, 4), (3, 6), (9), (7, 3), (4), (8, 2), (1, 6, 3), (7) 一种可能的组合。关于 (1), (5), (4), (3), (6), (9), (7), (4), (3), (8), (2) 你要说什么, (1), (6), (3), (7)
  • @AmanDeepGautam 我认为第一个应该是有效的。第二个不是。我想在每一刻都得到最好的(最接近 N 的总和)组合。有些事情像使用贪心算法,但我不想使用它,因为它不会给我最好的组合。我的目标是获得子集,如果我这样做Sum(N-Sum(subset)),我将获得最小值
  • 首先你必须对你的列表进行排序,然后从最大数量到最小数量,每个部分的长度接近n。这个问题就像this问题。

标签: algorithm combinations


【解决方案1】:

有限集 S 的简单 k 组合是 S 的 k 个不同元素的子集。指定子集不会以特定顺序排列它们。

您可以使用 CombinatoricsLib。 CombinatoricsLib 是一个用于生成组合对象的 java 库。 https://code.google.com/p/combinatoricslib/

使用这个:

    public static void main(String[] args) {

           // Create the initial vector
           ICombinatoricsVector<Integer> initialVector = Factory.createVector(
              new Integer[]  {1, 5, 4, 3, 6, 9, 7, 4, 3, 8, 2, 1, 6, 3, 7} );          

           int subsetMaxSize = 5;
           int upperLimit = 10;  
           int lowerLimit = 8;
           for(int i = 1; i <= subsetMaxSize; i++)
           {
               Generator<Integer> gen = Factory.createSimpleCombinationGenerator(initialVector, i);
               for (ICombinatoricsVector<Integer> combination : gen)
               {
                   int sum = vectorSum(combination);
                   if(validateSum(sum, lowerLimit, upperLimit))
                       printVector(combination);
               }   
           }
    }

    public static boolean validateSum(Integer value, Integer lowerLimit, Integer upperLimit)
    {
        if(value <= upperLimit && value > lowerLimit)   
            return true;
        return false;           
    }

    public static Integer vectorSum(ICombinatoricsVector<Integer> vect)
    {
        Integer sum = 0;    
        for(int i = 0; i < vect.getSize(); i++) 
            sum += vect.getValue(i);
        return sum;
    }

    public static void printVector(ICombinatoricsVector<Integer> vect)
    {
        String output = ""; 
        for(int i = 0; i < vect.getSize(); i++)
            output += vect.getValue(i) + ", ";
        System.out.println(output);
    }

将返回输出

9, 
1, 9, 
1, 8, 
5, 4, 
5, 4, 
4, 6, 
4, 6, 
3, 6, 
3, 7, 
3, 6, 
3, 7, 
6, 4, 
6, 3, 
6, 3, 
9, 1, 
7, 3, 
7, 2, 
7, 3, 
4, 6, 
3, 6, 
3, 7, 
8, 2, 
8, 1, 
2, 7, 
6, 3, 
3, 7, 
1, 5, 4, 
1, 5, 3, 
1, 5, 4, 
1, 5, 3, 
1, 5, 3, 
1, 4, 4, 
1, 3, 6, 
1, 3, 6, 
1, 6, 3, 
1, 6, 2, 
1, 6, 3, 
1, 7, 2, 
1, 7, 1, 
1, 3, 6, 
1, 8, 1, 
1, 2, 6, 
1, 2, 7, 
1, 1, 7, 
1, 6, 3, 
5, 4, 1, 
5, 3, 2, 
5, 3, 1, 
5, 4, 1, 
5, 3, 2, 
5, 3, 1, 
5, 2, 3, 
5, 1, 3, 
4, 3, 3, 
4, 3, 2, 
4, 3, 3, 
4, 4, 2, 
4, 4, 1, 
4, 3, 2, 
4, 3, 3, 
4, 2, 3, 
3, 6, 1, 
3, 4, 3, 
3, 4, 2, 
3, 4, 3, 
3, 3, 3, 
3, 1, 6, 
6, 3, 1, 
6, 2, 1, 
6, 1, 3, 
7, 2, 1, 
4, 3, 2, 
4, 3, 3, 
4, 2, 3, 
3, 1, 6, 
2, 1, 6, 
2, 1, 7, 
1, 6, 3, 
1, 5, 3, 1, 
1, 5, 3, 1, 
1, 5, 2, 1, 
1, 5, 1, 3, 
1, 4, 3, 2, 
1, 4, 3, 1, 
1, 4, 4, 1, 
1, 4, 3, 2, 
1, 4, 3, 1, 
1, 4, 2, 3, 
1, 4, 1, 3, 
1, 3, 4, 2, 
1, 3, 4, 1, 
1, 3, 3, 2, 
1, 3, 3, 3, 
1, 3, 2, 3, 
1, 6, 2, 1, 
1, 4, 3, 2, 
1, 4, 3, 1, 
1, 4, 2, 3, 
1, 4, 1, 3, 
1, 3, 2, 3, 
1, 2, 1, 6, 
4, 3, 2, 1, 
4, 3, 2, 1, 
4, 2, 1, 3, 
3, 4, 2, 1, 
3, 3, 2, 1, 
3, 3, 1, 3, 
3, 2, 1, 3, 
4, 3, 2, 1, 
4, 2, 1, 3, 
3, 2, 1, 3, 
1, 3, 3, 2, 1, 
1, 3, 2, 1, 3, 
1, 3, 2, 1, 3, 

【讨论】:

    【解决方案2】:

    您可以使用递归,但是如果您能说出您的原始问题和限制条件,那么可能会有更好的解决方案。对于递归,它将是这样的:

    list = {1, 5, 4, 3, 6, 9, 7, 4, 3, 8, 2, 1, 6, 3, 7};
    result = {};
    
    function rec(index, max_sum) {
        if(index >= list.length) {
            print result;
            return;
        }
        for each list[i] where i >= index {
            // Case 1 - we take current element and go further
            if(list[i] <= max_sum) {
                result.insert(list[i]);
                rec(index + 1, max_sum - list[i]);
                result.remove(list[i]);
            }
    
            // Case 2 - we skip current element
            rec(index + 1, max_sum);
        }
    }
    
    N = 10;
    rec(0, N);
    

    这只会生成所有可能的数字总和不超过 N 的组合。

    【讨论】:

      猜你喜欢
      • 2011-09-05
      • 2015-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-24
      • 1970-01-01
      • 2021-05-26
      • 2012-05-17
      相关资源
      最近更新 更多