【问题标题】:All possible Combinations using Dynamic Programming使用动态规划的所有可能组合
【发布时间】:2017-06-04 15:37:42
【问题描述】:

我有一个简单的数学问题。 这是一个数组。

数组 = { 1, 2, 3 }

需要上述数组元素的所有可能组合,使总和 = 5。

解:{ 1, 1, 1, 1, 1 } { 1, 1, 1, 2 } { 1, 2, 2 } { 2, 3 } { 1, 1, 3 }

注意:只要总和为 5,您可以使用任意数组元素任意次数。

        int weight = 5;
        List<int> weights = new List<int>() { 1, 2 ,3};


   void function1(int weight,List<int> weights, List<List<int>> combinationlist)
    { 
    for (int i = 0; i < weights.Count; i++)
        {
            if (weight % weights[i] == 0)
            {
                int num = weight / weights[i];
                List<int> mylist = new List<int>();
                for (int j = 0; j < num; j++)
                {
                    mylist.Add(weights[i]);

                }

                if (!combinationlist.Contains(mylist))
                    combinationlist.Add(mylist);
            }


        }


    }

现在上面的函数生成了{1,1,1,1,1}解的简单组合。

    void function2(int weight, List<int> weights, List<List<int>> combinationlist)
    {
        int i = weights.Count - 1;
        Stack<int> mystack = new Stack<int>();
        List<int> combinationarray = new List<int>();


        foreach (var x in weights)
            mystack.Push(x);

        for (;i >= 0; i--)
        {
            if (weight <= weights[i])
                mystack.Pop();  
        }


        int remainder = 0;


        if (weight % mystack.Peek() != 0)
            remainder = weight % mystack.Peek();

            int quotient = weight / mystack.Peek();

            combine(combinationlist,combinationarray,mystack,quotient,remainder);


    }

组合功能

void combine(List<List<int>>combinations,List<int>combination,Stack<int> mystack,int quotient, int remweight)
    {

        for (int i = 0; i < quotient; i++)
        {

            combination.Add(mystack.Peek());
        }

        if (remweight > 1)
            remweight = remweight - mystack.Peek() * quotient;
        else if (remweight == 0)
        {
            if (!combinations.Contains(combination))
                combinations.Add(combination);

            return;

        }

        else
            return;

        while (mystack.Peek() > remweight )
        {
            if (mystack.Count != 0)
                mystack.Pop();
        }

        quotient = remweight / mystack.Peek();


combine(combinations, combination, mystack, quotient, remweight);


        }

所有这些工作。我只能得到两个解决方案 {2,1,1,1} {1,1,1,1,1}。

【问题讨论】:

  • 你试过什么?你得到什么错误?所以不是来做你的功课的:)
  • 你有没有尝试解决这个问题?到目前为止,您做了哪些考虑?我们在这里不仅仅是为您解决问题,展示您的努力以及您出错的地方,我们将帮助您走上正确的轨道
  • 更大问题的一部分。我努力了。没有得到所有可能的答案。
  • 请展示您的尝试,以便我们知道您在问题上的立场。
  • 为什么这被标记为“动态规划”?是否明确要求动态编程?输入中的所有数字都可以假设为正吗?是否允许 0?

标签: algorithm recursion dynamic-programming


【解决方案1】:

我将在 python 中提供答案,因为它很好地说明了算法。对于此类问题,Python 几乎就像是伪代码。

# curr: a temporary list that is used only for printing the result
# arr: the list of input values
# val: the number we want to sum to
# currval: the number used so far (that will be the maximum number used so far)
def recursive_combos(curr, arr, val, currval):
    for item in arr:
        if item < currval:
            continue
        if val - item < 0:
            return
        if val - item == 0:
            print curr + [item]
            continue
        recursive_combos(curr + [item], arr, val - item, item)
    return

def combos(arr, val):
    recursive_combos([], sorted(arr), 5, min(arr) - 1)

combos([3, 1, 2], 5)

答案:

[1, 1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 3]
[1, 2, 2]
[2, 3]

这是递归的基本说明,我认为代码大部分是不言自明的。

此解决方案需要注意的关键事项是:

  1. 需要对数组进行排序以帮助消除重复项
  2. 需要存在第 4 个参数以消除重复项。我认为您会发现消除它并尝试代码是一个有用的练习。可能有一种更简洁的方法,而不是传递第四个参数,您可以尝试一下。
  3. 这不使用作为动态编程的另一个关键组件的记忆。这将需要将结果存储在某处以获取值并查找答案。不过,它可以很容易地插入。

【讨论】:

    【解决方案2】:

    以下方法简化并获得所有解决方案(代码为 Racket 编程语言)。注释解释了正在执行的过程:

    (define L '(0 1 2 3))       ; ADD 0 TO THE LIST; 
    
    (define outl
      (for*/list (   ; TRY ALL COMBINATIONS CHOOSING 5 NUMBERS FROM ABOVE LIST;
                     ; SINCE THAT IS MAXIMUM NUMBER OF ELEMENTS THAT CAN ADD UP TO 5;
                     ; REPETITION IS ALLOWED;
                  (i L)
                  (j L)
                  (k L)
                  (m L)
                  (n L)
                  #:when (= 5 (+ i j k m n)))   ; USE COMBINATION ONLY IF SUM IS 5;
      (remove* (list 0)                         ; REMOVE 0s FROM THIS COMBINATION;
               (sort (list i j k m n) <))))     ; SORT COMBINATION;
    
    (remove-duplicates outl)                    ; REMOVE DUPLICATES FROM LIST; 
    

    输出是答案列表的列表:

    '((2 3) (1 1 3) (1 2 2) (1 1 1 2) (1 1 1 1 1))
    

    另一种解决方案是使用递归来不断添加所有元素,直到达到(或超过)总和:

    (define L '(1 2 3))
    (define desired_sum 5)
    
    (define anslist '())       ; solutions will be added to this list;
    
    (let loop ((ol '()))       ; start with an empty list;
      (for ((i L))             ; try adding each element and see if desired sum is reached; 
        (cond
          [(= desired_sum (apply + (cons i ol)))  ; desired sum reached
           (set! anslist                          ; add sorted solution to anslist;
                 (cons (sort (cons i ol) <)       ; sorting needed to identify duplicates later;
                       anslist))]        
          [(> desired_sum (apply + (cons i ol)))  ; total is less than desired sum
           (loop (cons i ol))]                    ; so loop again to add more elements;
          )))                    ; discard (no looping) if desired sum is exceeded;
    
    (remove-duplicates anslist)  ; print after removing duplicate solutions;
    

    输出:

    '((2 3) (1 1 3) (1 2 2) (1 1 1 2) (1 1 1 1 1))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-19
      • 2019-04-14
      • 1970-01-01
      相关资源
      最近更新 更多