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
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:
- Compute sum of given multiset elements, sum of squares, sum of cubes.
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
来源:https://stackoverflow.com/questions/19723575/find-sum-of-subset-with-multiplication