高效算法计算所有k产品的总和

时间:2012-02-14 16:58:05

标签: algorithm combinatorics

假设您获得了Ln个数字和k<n整数的列表。有没有一种有效的方法来计算kL个不同数字的所有产品的总和?

例如,请L=[1,3,4,6]k=2。然后我要找的号码是

1*3 + 1*4 + 1*6 + 3*4 + 3*6 + 4*6

你能想到一种避免生成大小k的所有子集的方法吗?

6 个答案:

答案 0 :(得分:7)

设F(X,k,n)为数组X的前n个元素的k乘积和。

F(X,k,n)= F(X,k,n-1)+ F(X,k-1,n-1)* X [n]

您可以使用动态编程解决。复杂度= O(kn)。

F(X,k,n)的结束条件:当n = k F(X,k,k)= X [1] * X [2] * ... * X [n]

更多详情:

F(X,1,1) = X[1]
F(X,1,i) = F(X,1,i-1)+X[i] for i=2...n 

For j=2..n:
    For i = 1..k:
        if i<j:
            F(X,i,j) = F(X,i,j-1)+F(X,i-1,j-1)*X[j]
        else if i==j:
            F(X,i,j) = F(X,i-1,j-1)*X[j]
        else:
            pass

答案 1 :(得分:3)

是的,有办法。考虑多项式

(X + a[0]) * (X + a[1]) * ... * (X + a[n-1])

其系数只是k - 产品的总和,其度数为n,因此您可以为所有k计算所有k - 产品的总和同时进行O(n ^ 2)步骤。

s步之后,X s-k 的系数是第一个k数组元素的s - 乘积之和。第一个k元素的s+1 - 产品分为两类,即(s+1) st 元素 - 这些类型的格式为a[s]*((k-1) - 第一个s元素的产品 - 以及那些不涉及它们的产品 - 这些是k - 第一个s元素的产品。

代码使得result[i]是X i 的系数((n-i) - 产品的总和):

int *k_products_1(int *a, int n){
    int *new, *old = calloc((n+1)*sizeof(int));
    int d, i;
    old[0] = 1;
    for(d = 1; d <= n; ++d){
        new = calloc((n+1)*sizeof(int));
        new[0] = a[d-1]*old[0];
        for(i = 1; i <= d; ++i){
            new[i] = old[i-1] + a[d-1]*old[i];
        }
        free(old);
        old = new;
    }
    return old;
}

如果您只想要一个k的{​​{1}} - 产品的总和,则可以在索引k停止计算,给出O(n *(nk))算法 - 如果n-k那就好了。要获得k >= n/2的O(n * k)算法,必须反过来组织系数数组,以便k <= n/2是X nk 的系数(如果只需要一个总和,则在索引result[k]停止计算:

k

答案 2 :(得分:0)

你可以将k减少1:

e.g。对于k = 2

1*3 + 1*4 + 1*6 + 3*4 + 3*6 + 4*6

==

1*(3+4+6)+3*(4+6)+4*6

并且对于k = 3

1*3*4 + 1*3*6 + 3*4*6

==

1*3*(4+6) + 3*4*6

所以基本上你循环你的列表,然后递归到相同的算法,k减少1,只剩下列表的其余部分

答案 3 :(得分:0)

对于k = 2,

让我们s = SUM_x_in_L x(数字之和)和sq = SUM_x_in_L x^2(正方形之和)

然后它是SUM_x_in_L (s - x) * x / 2 = (s * s - sq) / 2

答案 4 :(得分:0)

您可以探索的一个有趣的属性是乘法与加法相关的分配属性。

L=[a,b,c,d]

当k = 1时,它是微不足道的:

S=a+b+c+d

当k = 2时:

S = a * (b + c + d) + b * (c + d) + c * d

当k = 3时,事情会变得更有趣:

S = a * b * ( c + d) + (c * d) * (a + b)
S = a * (b * (c + d)) + c * d) + b * (c * d)  <-- this form lends itself better to the algorithm

对于k = 4:

S = a * b * c * d

这应该适用于较大的n值。

C#中的实现:

 private static int ComputeSum(int[] array, int offset, int K)
 {
     int S = 0;

     if (K == 1)
     {                      
         for (int i = offset; i < array.Length; i++)
             S += array[i];
     }
     else if ((array.Length - offset) == K)
     {
         S = array[offset] * ComputeSum(array, offset + 1, K - 1);
     }
     else if (offset < array.Length)
     {
         S = ComputeSum(array, offset + 1, K) + array[offset] * ComputeSum(array, offset + 1, K - 1);             
     }

     return S;
 }

通过记忆可以进一步改进。

答案 5 :(得分:0)

代数地,对于k=2,只需取L的元素之和,将其平方,然后减去L的平方和。那就是:

int sum = 0;
int sqSum = 0;
for (int i=0; i<n; ++i) {
    sum += L[i];
    sqSum += L[i]*L[i];
}
return sum*sum - sqSum;

在您的示例中,您正在计算的是

(1 + 3 + 4 + 6)^2 - (1^2 + 3^2 + 4^2 + 6^2) = 1*3 + 1*4 + 1*6 + 3*4 + 3*6 + 4*6

这应该会为您提供一般性的提示。