What would be the best way (in C) to get all sums of N numbers in an array, by using addition and subtraction?
For example (N = 3):
arr[] = [30, 14, 2]
results:
-30-14-2 = -46
-30-14+2 = -42
-30+14-2 = -18
-30+14+2 = -14
30-14-2 = 14
30-14+2 = 18
30+14-2 = 42
30+14+2 = 46
As can be seen, there are 2^N solutions.
I also noticed that the addition an subtraction symbols alternate in the same way as binary counting (000 001 … 110 111), which might be useful.
Probably a recursive approach would be best, but I find it very hard to think recursively.
Therefore, I hope someone can explain to me what the best strategy would be to tackle this problem.
——————————
EDIT:
I have a working Python code, but this uses sets set(), which aren’t available in C. (arr is an array containing all numbers.)
out = set()
out.add(0)
for i in range(0, len(arr)):
tmp = set()
for j in out:
tmp.add(j + arr[i])
tmp.add(j - arr[i])
out = tmp
print(out)
——————————
EDIT:
With replacing the sets by arrays and making a few small changes, I got it working. Thanks to everyone who commented!
This is a case where recursion seems preferable to a data structure because the exponential nature of the problem means there's no risk of a stack overflow on any value of n you could realistically test, yet you can take advantage of the stack's implicit storage capabilities.
The recursive logic can be written very directly using an index i. The base case is when i >= n; print the sum you've accumulated. Otherwise, subtract the ith element from the sum and recurse on the rest of the numbers list without i. In a second branch, add the ith element to the sum and recurse on the rest of the numbers list without i. You could also shift elements off the array using a pointer instead if i as pointed out in the comments.
Note that this procedure will include duplicate results, so if you want to eliminate those, your original set idea is worth pursuing.
It's generally poor design to mix IO and logic in functions, but for simplicity's sake, I'll break that rule here:
#include <stdio.h>
void print_possible_sums(int nums_len, int *nums, int sum, int i) {
if (i >= nums_len) {
printf("%d\n", sum);
}
else {
print_possible_sums(nums_len, nums, sum - nums[i], i + 1);
print_possible_sums(nums_len, nums, sum + nums[i], i + 1);
}
}
int main() {
int arr[] = {30, 14, 2};
print_possible_sums(sizeof(arr) / sizeof(arr[0]), arr, 0, 0);
return 0;
}
Output:
-46
-42
-18
-14
14
18
42
46
I have made an algorithm that performs this problem. Maybe what I wrote is not as efficient as possible (so maybe it can be improved) but at least it works.
Let me know if it's okay.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define MAX 4
void cycle(int arr[MAX]);
int toRepeat(int arr[MAX], int s);
int main(){
int arr[MAX] = {1, 2, 3, 4};
cycle(arr);
}
void cycle(int arr[MAX]){
int a, ris;
a = pow(2, MAX);
for (int i= 0; i < a; i++){
ris = toRepeat(arr, i);
printf(" = %3d \n", ris);
}
}
int toRepeat(int arr[MAX], int s){
int pos = 0;
int ris = 0;
int a;
bool flag;
a = pow(2, MAX);
if (s < a/2) {
ris += arr[pos];
printf("+%d", arr[pos]);
} else {
ris -= arr[pos];
printf("-%d", arr[pos]);
}
pos++;
for (int i= 2; i < a; i = i * 2){
for (int j= 0; j < i/2; j++) {
if (s%i == j) {
ris += arr[pos];
printf("+%d", arr[pos]);
pos++;
flag = true;
break;
}
}
if (!flag){
ris -= arr[pos];
printf("-%d", arr[pos]);
pos++;
}
flag = false;
}
return ris;
}
Output:
+1+2+3+4 = 10
+1-2+3+4 = 6
+1+2-3+4 = 4
+1-2-3+4 = 0
+1+2+3-4 = 2
+1-2+3-4 = -2
+1+2-3-4 = -4
+1-2-3-4 = -8
-1+2+3+4 = 8
-1-2+3+4 = 4
-1+2-3+4 = 2
-1-2-3+4 = -2
-1+2+3-4 = 0
-1-2+3-4 = -4
-1+2-3-4 = -6
-1-2-3-4 = -10
Me too, me too!
Keep one array with bool negative[3 + 1] = {0};. Calculate sum of array[i] * (negative[i]?-1:1) at each step. Each step increments the next value in negative as if it would be a binary number. The loop ends when the highest element negative[3] is true - so we want through all possibilities.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
int calc_sum(size_t len, const int vals[len], const bool negative[len]) {
int sum = 0;
for (size_t i = 0; i < len; ++i) {
sum += vals[i] * (negative[i] ? -1 : 1);
}
return sum;
}
bool *sequence_init(size_t len) {
// error checking omitted
return calloc(len + 1, sizeof(bool));
}
bool sequence_continue(size_t len, bool t[len + 1]) {
assert(t);
const bool go_on = !t[len];
if (!go_on) {
// automatically free on loop end
free(t);
}
return go_on;
}
void sequence_next(size_t len, bool t[len + 1]) {
assert(t);
for (size_t i = 0; i < len + 1; ++i) {
if (!t[i]) {
t[i] = 1;
break;
} else {
t[i] = 0;
}
}
}
int main() {
const int vals[3] = { 30, 14, 2 };
const size_t len = 3;
for(
bool *sequence = sequence_init(len);
sequence_continue(len, sequence);
sequence_next(len, sequence)
) {
for (size_t i = 0; i < len; ++i) {
printf("%2d*%d %c ",
sequence[i]?-1:1,
vals[i],
i + 1 != len ? '+' : '='
);
}
const int sum = calc_sum(len, vals, sequence);
printf("%d\n", sum);
}
}
The code outputs:
1*30 + 1*14 + 1*2 = 46
-1*30 + 1*14 + 1*2 = -14
1*30 + -1*14 + 1*2 = 18
-1*30 + -1*14 + 1*2 = -42
1*30 + 1*14 + -1*2 = 42
-1*30 + 1*14 + -1*2 = -18
1*30 + -1*14 + -1*2 = 14
-1*30 + -1*14 + -1*2 = -46