从数字列表中获取所有可能的总和

时间:2016-08-31 09:57:11

标签: dynamic-programming

假设我有一个数字列表:2,2,5,7

现在算法的结果应该包含所有可能的总和。

在这种情况下:2 + 2,2 + 5,5 + 7,2 + 2 + 5,2 + 2 + 5 + 7,2 + 5 + 7,5 + 7

我想通过动态编程实现这一目标。我尝试使用矩阵但到目前为止我还没有找到一种方法来获得所有可能性。

4 个答案:

答案 0 :(得分:2)

基于这个问题,我认为AT-2016发布的答案是正确的,并且没有可以利用动态编程概念来降低复杂性的解决方案。

以下是如何利用动态编程来解决类似的问题,该问题要求返回所有可能的子序列和的总和。

考虑数组{2,2,5,7}:不同的可能子序列是:

{2},{2},{5},{7},{2,5},{2,5},{5,7},{2,5,7},{2,5, 7},{2,2,5,7},{2,2},{2,7},{2,7},{2,2,7-},{2,2,5}

因此,问题是从所有这些子序列中找到所有这些元素的总和。 动态编程来救援!!

根据每个子序列的结束元素排列子序列:

  1. 以第一个元素结尾的子序列:{2}
  2. 以第二个元素结尾的子序列:{2},{2,2}
  3. 以第三个元素结尾的子序列:{5},{2,5},{2,5},{2,2,5}
  4. 以第四个元素结尾的子序列:{7},{5,7},{2,7},{2,7},{2,2,7},{2,5,7},{2 ,5,7-},{2,2,5,7}。
  5. 以下是代码段:

    数组的[]'分别计算1,2,3,4的总和,也就是说,s [2]计算以第三个元素结尾的所有子序列的总和。数组'dp []'计算到目前为止的总和。

     s[0]=array[0];
     dp[0]=s[0];
     k = 2;
     for(int i = 1; i < n; i ++)
     {
        s[i] = s[i-1] + k*array[i];
        dp[i] = dp[i-1] + s[i];
        k = k * 2;
     }
     return dp[n-1];
    

答案 1 :(得分:1)

这是在C#和数组中完成的,用于查找我之前使用的可能总和:

static void Main(string[] args)
{
    //Set up array of integers
    int[] items = { 2, 2, 5, 7 };

    //Figure out how many bitmasks is needed

    //4 bits have a maximum value of 15, so we need 15 masks.
    //Calculated as: (2 ^ ItemCount) - 1
    int len = items.Length;
    int calcs = (int)Math.Pow(2, len) - 1;

    //Create array of bitmasks. Each item in the array represents a unique combination from our items array
    string[] masks = Enumerable.Range(1, calcs).Select(i => Convert.ToString(i, 2).PadLeft(len, '0')).ToArray();

    //Spit out the corresponding calculation for each bitmask
    foreach (string m in masks)
    {
        //Get the items from array that correspond to the on bits in the mask
        int[] incl = items.Where((c, i) => m[i] == '1').ToArray();

        //Write out the mask, calculation and resulting sum
        Console.WriteLine(
            "[{0}] {1} = {2}",
            m,
            String.Join("+", incl.Select(c => c.ToString()).ToArray()),
            incl.Sum()
        );
    }

    Console.ReadKey();
}

可能的输出:

[0001] 7 = 7
[0010] 5 = 5
[0011] 5 + 7 = 12
[0100] 2 = 2

答案 2 :(得分:0)

这不是问题的答案,因为它没有演示动态编程的应用。相反,它注意到这个问题涉及 multisets ,Sympy可以使用这些设施。

>>> from sympy.utilities.iterables import multiset_combinations
>>> numbers = [2,2,5,7]
>>> sums = [ ]
>>> for n in range(2,1+len(numbers)):
...     for item in multiset_combinations([2,2,5,7],n):
...         item
...         added = sum(item)
...         if not added in sums:
...             sums.append(added)
...             
[2, 2]
[2, 5]
[2, 7]
[5, 7]
[2, 2, 5]
[2, 2, 7]
[2, 5, 7]
[2, 2, 5, 7]
>>> sums.sort()
>>> sums
[4, 7, 9, 11, 12, 14, 16]

答案 3 :(得分:0)

我有一个解决方案,可以打印所有可能的子集总和的列表。 它不是动态规划(DP),但这种解决方案比 DP 方法更快。

void solve(){
    ll i, j, n;
    cin>>n;
    vector<int> arr(n);
    const int maxPossibleSum=1000000;
    for(i=0;i<n;i++){
        cin>>arr[i];
    }
    bitset<maxPossibleSum> b;
    b[0]=1;
    for(i=0;i<n;i++){
        b|=b<<arr[i];
    }
    for(i=0;i<maxPossibleSum;i++){
        if(b[i])
            cout<<i<<endl;
    }
}
Input:
First line has the number of elements N in the array.
The next line contains N space-separated array elements.
4
2 2 5 7

----------
Output:
0
2
4
5
7
9
11
12
14
16

这个方案的时间复杂度是 O(N * maxPossibleSum/32)
该解决方案的空间复杂度为 O(maxPossibleSum/8)