質問

Let's say we have got a set

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

The goal is to find a sum that we create in the following way: We find all subsets whose length is 3, then multiply each subset's elements (for the subset {b_1, b_2, b_3} the result will be b_1*b_2*b_3). At the end we sum up all these products.

I am looking for a shortest time-execution algorithm.

Example

SET: {3, 2, 1, 2}

Let S be our sum.

S = 3*2*1 + 3*2*2 + 2*1*2 + 3*1*2 = 28
役に立ちましたか?

解決 2

It is easier to calculate sum of multiplied triplets when repetitions are allowed (like a_1*a_1*a_1). This sum is just (sum^3).

Since repetitions are not allowed, we could just subtract them: (sum^3 - 3*sumsquares*sum).

But the above formula subtracts elements on main diagonal 3 times while it should be subtracted only once. Need to compensate this: (sum^3 - 3*sumsquares*sum + 2*sumcubes).

The above formula does not take into account 3! permutations of each triplet. So it should be divided by 3!.

Finally we have a linear-time algorithm:

  1. Compute sum of given multiset elements, sum of squares, sum of cubes.
  2. result = (sum^3 - 3*sumsquares*sum + 2*sumcubes)/6

他のヒント

Here is an O(n^2) approach:

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)

It works because for each two elements x,y you need to sum x*y*z (for all elements z), but the sum of all possible z values is SUM(list) - x - y.

So, instead of doing: x*y*z1 + x*y*z2 + ... + x*y*z(n-2) , you basically do x*y*(z1 + ... + z(n-2))

EDIT: Editted multi-counting due to not multiplying only in the 'tail', as mentioned by @AbhishekBansal . You need to multiply each element only with the 'tail' of the list, where the tail is all the elements after the last element among x,y.

Full Working Code in C++ (Following up on Amit's idea)

#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;
}

Output:

28
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top