In case of your first idea:
Your first idea of trying every possible combination one after another and checking summation will definitely work but the problem is that complexity will be very high.
For this, we can simply do like this:
bool recursion(int pos, int n, int sum, vector<int>&sequence) {
if (pos == n) {
if (sum == 0) return true;
else return false;
}
bool resultTakingPositive = recursion(pos + 1, n, sum + sequence[pos], sequence);
bool resultTakingNegative = recursion(pos + 1, n, sum - sequence[pos], sequence);
if (resultTakingPositive || resultTakingNegative) return true;
else return false;
}
If there are total n integer numbers, then this solution will take time complexity of O(2^n). Because in every position, there are two options :
- Take +ve value in summation.
- Take -ve value in summation.
And, we have to make choice for every n integer numbers. So, n times multiplication of 2 leads to O(2^n) time complexity.
In case of your second idea:
You are trying to sort the sequence first in non-increasing order and assigning +ve sign to the first number, then subtracting until you get negative number, then adding again until you get positive number. Unfortunately, this greedy approach does not work always. For example:
In a sequence: 5, 4, 4, 3, 2
If we try this approach we will have : +5 -4 -4 +3 +2 which leads to summation = 2.
But, we can make summation zero by doing : +5 +4 -4 -3 -2 .
Efficient approach:
We can use memoization in above recursive solution with simple modification so as to allow positive indexing while doing memoization with states being pos and sum. This is also called dynamic programming. For this, the highest possible value of pos * sum should be less so as to cache their states in memory using two dimensional array. So, time and space complexity both will be O(n * sum). Example of this approach using c++ code will be:
#include<bits/stdc++.h>
using namespace std;
bool recursion(int pos, int n, int sum, vector<int>&sequence,int &baseSum, vector< vector<int> >&dp) {
if (pos == n) {
if (sum == baseSum) return true;
else return false;
}
if (dp[pos][sum] != -1) return dp[pos][sum];
bool resultTakingPositive = recursion(pos + 1, n, sum + sequence[pos], sequence, baseSum, dp);
bool resultTakingNegative = recursion(pos + 1, n, sum - sequence[pos], sequence, baseSum, dp);
dp[pos][sum] = (resultTakingPositive || resultTakingNegative);
return dp[pos][sum];
}
int main() {
vector<int>sequence;
int n, baseSum = 0;
scanf("%d",&n);
for (int i = 1; i <= n; i++) {
int x;
scanf("%d",&x);
sequence.push_back(x);
baseSum += x;
}
vector< vector<int> >dp(n, vector<int>(2*baseSum + 1, -1));
cout<<recursion(0, n, baseSum, sequence, baseSum, dp)<<endl;
return 0;
}
Now, If we want to keep track of signs used to make up the summation 0, we may do this by analysing recursive calls as follows:
#include<bits/stdc++.h>
using namespace std;
bool recursion(int pos, int n, int sum, vector<int>&sequence,int &baseSum, vector< vector<int> >&dp) {
if (pos == n) {
if (sum == baseSum) return true;
else return false;
}
if (dp[pos][sum] != -1) return dp[pos][sum];
bool resultTakingPositive = recursion(pos + 1, n, sum + sequence[pos], sequence, baseSum, dp);
bool resultTakingNegative = recursion(pos + 1, n, sum - sequence[pos], sequence, baseSum, dp);
dp[pos][sum] = (resultTakingPositive || resultTakingNegative);
return dp[pos][sum];
}
void printSolution(int pos, int n, int sum, vector<int>&sequence,int &baseSum, vector< vector<int> >&dp) {
if (pos == n) {
cout<<endl;
return;
}
bool resultTakingPositive = recursion(pos + 1, n, sum + sequence[pos], sequence, baseSum, dp);
if (resultTakingPositive == true) {
cout<< "+ ";
printSolution(pos + 1, n, sum + sequence[pos], sequence, baseSum, dp);
} else {
cout<< "- ";
printSolution(pos + 1, n, sum - sequence[pos], sequence, baseSum, dp);
}
}
int main() {
vector<int>sequence;
int n, baseSum = 0;
scanf("%d",&n);
for (int i = 1; i <= n; i++) {
int x;
scanf("%d",&x);
sequence.push_back(x);
baseSum += x;
}
vector< vector<int> >dp(n, vector<int>(2*baseSum + 1, -1));
if (recursion(0, n, baseSum, sequence, baseSum, dp)) { // if possible to make sum 0 then
printSolution(0, n, baseSum, sequence, baseSum, dp);
}
return 0;
}