用乘法求出子集的总和

时间:2013-11-01 08:54:57

标签: algorithm sum subset multiplying subset-sum

假设我们有一套

{a_1, a_2, a_3, ..., a_n}

目标是找到我们以下列方式创建的总和:我们找到长度为3的所有子集,然后将每个子集的元素相乘(对于子集{b_1, b_2, b_3},结果将为b_1*b_2*b_3 )。最后,我们总结了所有这些产品。

我正在寻找最短的时间执行算法。

实施例

SET: {3, 2, 1, 2}

Let S be our sum.

S = 3*2*1 + 3*2*2 + 2*1*2 + 3*1*2 = 28

3 个答案:

答案 0 :(得分:5)

以下是O(n^2)方法:

sum = SUM(list)
answer = 0
for each i from 0 to n:
   sum -= list[i]
   remains = sum
   for each j from i+1 to n:
      remains -= list[j]
      answer += list[i] * list[j] * (remains)

这是有效的,因为对于每两个元素x,y,您需要求和x*y*z(对于所有元素z),但所有可能z值的总和为{{ 1}}。

所以,不是做SUM(list) - x - y,而是基本做x*y*z1 + x*y*z2 + ... + x*y*z(n-2)

编辑:由于@AbhishekBansal所提及的“尾部”不会增加而编辑多次计数。您需要将每个元素仅与列表的“尾部”相乘,其中尾部是x*y*(z1 + ... + z(n-2))中最后一个元素之后的所有元素。

答案 1 :(得分:2)

C ++中的完整工作代码(跟随Amit的想法)

#include <iostream>

using namespace std;

int main()
{
    int s[] = {3, 2, 1, 2};

    double sumOfFullList = 0;
    for ( int i = 0; i < 4; i++ )
        sumOfFullList += s[i];

    double sum = 0;

    for ( int i = 0; i < 4; i++ ) {
      double sumOfList = sumOfFullList - s[i];
      sumOfFullList -= s[i];
      for ( int j = i+1; j < 4; j++ ) {
          sumOfList -= s[j];
          sum += s[i]*s[j]*(sumOfList);
          //cout << s[i] << " " << s[j] << " " << sumOfList;
      }
    }

    cout << sum << endl;
    return 0;
}

输出:

28

答案 2 :(得分:1)

在允许重复时更容易计算乘法三元组的总和(如a_1 * a_1 * a_1)。这笔金额只是(sum^3)

由于不允许重复,我们可以减去它们:(sum^3 - 3*sumsquares*sum)

但是上面的公式减去主对角线上的元素3次,而应该只减去一次。需要补偿:(sum^3 - 3*sumsquares*sum + 2*sumcubes)

上面的公式没有考虑到3!每个三元组的排列。所以它应该除以3!

最后我们有一个线性时间算法:

  1. 计算给定多部分元素的总和,平方和,立方体之和。
  2. result = (sum^3 - 3*sumsquares*sum + 2*sumcubes)/6