Minimize count of flips required to make sum of the given array equal to 0
Given an array arr[] consisting of N integers, the task is to minimize the count of elements required to be multiplied by -1 such that the sum of array elements is 0. If it is not possible to make the sum 0, print “-1”.
Examples:
Input: arr[] = {2, 3, 1, 4}
Output: 2
Explanation:
Multiply arr[0] by -1. Therefore, the array modifies to {-2, 3, 1, 4}.
Multiply arr[1] by -1. Therefore, the array modifies to {-2, -3, 1, 4}
Therefore, the sum of the modified array is 0 and the minimum operations required is 2.Input: arr[] = {2}
Output: -1
Naive Approach: The simplest approach is to divide the array into two subsets in every possible way. For each division, check if the difference of their subset-sum is 0 or not. If found to be 0, then the length of the smaller subset is the result.
Time Complexity: O(2N)
Auxiliary Space: O(N)
Efficient Approach: To optimize the above approach, the idea is to use Dynamic Programming. Follow the steps to solve the problem:
- To make the sum of all array elements equal to 0, divide the given array elements into two subsets having an equal sum.
- Out of all the subsets possible of the given array, the subset whose size is the minimum of all is chosen.
- If the sum of the given array is odd, no subset is possible to make the sum 0, hence return -1
- Else, try all possible subset sums of the array and check if the sum of the subset is equal to sum/2. where the sum is the sum of all elements of the array.
- The recurrence relation of dp[] is:
dp(i, j) = min (dp(i+1, j – arr[i]]+1), dp(i+1, j))
where
dp (i, j) represents the minimum operations to make sum j equal to 0 using elements having index [i, N-1].
j represents the current sum.
i represents the current index.
- Using the above recurrence, print dp(0, sum/2) as the result.
Below is the implementation of the above approach:
C++
// C++ program for the above approach #include <bits/stdc++.h> using namespace std; // Initialize dp[][] int dp[2001][2001]; // Function to find the minimum number // of operations to make sum of A[] 0 int solve(vector< int >& A, int i, int sum, int N) { // Initialize answer int res = 2001; // Base case if (sum < 0 or (i == N and sum != 0)) { return 2001; } // Otherwise, return 0 if (sum == 0 or i >= N) { return dp[i][sum] = 0; } // Pre-computed subproblem if (dp[i][sum] != -1) { return dp[i][sum]; } // Recurrence relation for finding // the minimum of the sum of subsets res = min(solve(A, i + 1, sum - A[i], N) + 1, solve(A, i + 1, sum, N)); // Return the result return dp[i][sum] = res; } // Function to find the minimum number // of elements required to be flipped // to make sum the array equal to 0 void minOp(vector< int >& A, int N) { int sum = 0; // Find the sum of array for ( auto it : A) { sum += it; } if (sum % 2 == 0) { // Initialise dp[][] with -1 memset (dp, -1, sizeof (dp)); int ans = solve(A, 0, sum / 2, N); // No solution exists if (ans < 0 || ans > N) { cout << "-1" << endl; } // Otherwise else { cout << ans << endl; } } // If sum is odd, no // subset is possible else { cout << "-1" << endl; } } // Driver Code int main() { vector< int > A = { 2, 3, 1, 4 }; int N = A.size(); // Function Call minOp(A, N); return 0; } |
Java
// Java program for the above approach class GFG { // Initialize dp[][] static int [][]dp = new int [ 2001 ][ 2001 ]; // Function to find the minimum number // of operations to make sum of A[] 0 static int solve( int []A, int i, int sum, int N) { // Initialize answer int res = 2001 ; // Base case if (sum < 0 || (i == N && sum != 0 )) { return 2001 ; } // Otherwise, return 0 if (sum == 0 || i >= N) { return dp[i][sum] = 0 ; } // Pre-computed subproblem if (dp[i][sum] != - 1 ) { return dp[i][sum]; } // Recurrence relation for finding // the minimum of the sum of subsets res = Math.min(solve(A, i + 1 , sum - A[i], N) + 1 , solve(A, i + 1 , sum, N)); // Return the result return dp[i][sum] = res; } // Function to find the minimum number // of elements required to be flipped // to make sum the array equal to 0 static void minOp( int []A, int N) { int sum = 0 ; // Find the sum of array for ( int it : A) { sum += it; } if (sum % 2 == 0 ) { // Initialise dp[][] with -1 for ( int i = 0 ; i < 2001 ; i++) { for ( int j = 0 ; j < 2001 ; j++) { dp[i][j] = - 1 ; } } int ans = solve(A, 0 , sum / 2 , N); // No solution exists if (ans < 0 || ans > N) { System.out.print( "-1" + "\n" ); } // Otherwise else { System.out.print(ans + "\n" ); } } // If sum is odd, no // subset is possible else { System.out.print( "-1" + "\n" ); } } // Driver Code public static void main(String[] args) { int []A = { 2 , 3 , 1 , 4 }; int N = A.length; // Function Call minOp(A, N); } } // This code is contributed by 29AjayKumar |
Python3
# Python program for the above approach # Initialize dp[][] dp = [[ - 1 for i in range ( 2001 )] for j in range ( 2001 )] # Function to find the minimum number # of operations to make sum of A[] 0 def solve(A, i, sum , N): # Initialize answer res = 2001 # Base case if ( sum < 0 or (i = = N and sum ! = 0 )): return 2001 # Otherwise, return 0 if ( sum = = 0 or i > = N): dp[i][ sum ] = 0 return 0 # Pre-computed subproblem if (dp[i][ sum ] ! = - 1 ): return dp[i][ sum ] # Recurrence relation for finding # the minimum of the sum of subsets res = min (solve(A, i + 1 , sum - A[i], N) + 1 , solve(A, i + 1 , sum , N)) # Return the result dp[i][ sum ] = res return res # Function to find the minimum number # of elements required to be flipped # to make sum the array equal to 0 def minOp(A, N): sum = 0 # Find the sum of array for it in A: sum + = it if ( sum % 2 = = 0 ): # Initialise dp[][] with -1 dp = [[ - 1 for i in range ( 2001 )] for j in range ( 2001 )] ans = solve(A, 0 , sum / / 2 , N) # No solution exists if (ans < 0 or ans > N): print ( "-1" ) # Otherwise else : print (ans) # If sum is odd, no # subset is possible else : print ( - 1 ) # Driver Code A = [ 2 , 3 , 1 , 4 ] N = len (A) # Function Call minOp(A, N) # This code is contributed by rohitsingh07052. |
C#
// C# program for the above approach using System; using System.Collections.Generic; public class GFG { // Initialize [,]dp static int [,]dp = new int [2001,2001]; // Function to find the minimum number // of operations to make sum of []A 0 static int solve( int []A, int i, int sum, int N) { // Initialize answer int res = 2001; // Base case if (sum < 0 || (i == N && sum != 0)) { return 2001; } // Otherwise, return 0 if (sum == 0 || i >= N) { return dp[i, sum] = 0; } // Pre-computed subproblem if (dp[i, sum] != -1) { return dp[i, sum]; } // Recurrence relation for finding // the minimum of the sum of subsets res = Math.Min(solve(A, i + 1, sum - A[i], N) + 1, solve(A, i + 1, sum, N)); // Return the result return dp[i, sum] = res; } // Function to find the minimum number // of elements required to be flipped // to make sum the array equal to 0 static void minOp( int []A, int N) { int sum = 0; // Find the sum of array foreach ( int it in A) { sum += it; } if (sum % 2 == 0) { // Initialise [,]dp with -1 for ( int i = 0; i < 2001; i++) { for ( int j = 0; j < 2001; j++) { dp[i, j] = -1; } } int ans = solve(A, 0, sum / 2, N); // No solution exists if (ans < 0 || ans > N) { Console.Write( "-1" + "\n" ); } // Otherwise else { Console.Write(ans + "\n" ); } } // If sum is odd, no // subset is possible else { Console.Write( "-1" + "\n" ); } } // Driver Code public static void Main(String[] args) { int []A = { 2, 3, 1, 4 }; int N = A.Length; // Function Call minOp(A, N); } } // This code is contributed by 29AjayKumar |
Javascript
<script> // JavaScript program for the above approach // Initialize dp[][] let dp= []; for ( var i=0; i<2001; i++) { dp[i] = []; for ( var j=0; j<2001; j++) { dp[i][j] = -1; } } // Function to find the minimum number // of operations to make sum of A[] 0 function solve( A, i, sum, N){ // Initialize answer let res = 2001; // Base case if (sum < 0 || (i == N && sum != 0)) { return 2001; } // Otherwise, return 0 if (sum == 0 || i >= N) { dp[i][sum] = 0; return dp[i][sum]; } // Pre-computed subproblem if (dp[i][sum] != -1) { return dp[i][sum]; } // Recurrence relation for finding // the minimum of the sum of subsets res = Math.min(solve(A, i + 1, sum - A[i], N) + 1, solve(A, i + 1, sum, N)); // Return the result dp[i][sum] = res; return dp[i][sum]; } // Function to find the minimum number // of elements required to be flipped // to make sum the array equal to 0 function minOp(A, N){ let sum = 0; // Find the sum of array for (let i =0; i< A.length; i++) { sum += A[i]; } if (sum % 2 == 0) { let dp= []; for ( var i=0; i<2001; i++) { dp[i] = []; for ( var j=0; j<2001; j++) { dp[i][j] = -1; } } let ans = solve(A, 0, Math.floor(sum / 2), N); // No solution exists if (ans < 0 || ans > N) { document.write( "-1 <br>" ); } // Otherwise else { document.write(ans, "<br>" ); } } // If sum is odd, no // subset is possible else { document.write( "-1 <br>" ); } } // Driver Code let A = [ 2, 3, 1, 4 ]; let N = A.length; // Function Call minOp(A, N); </script> |
2
Time Complexity: O(S*N), where S is the sum of the given array.
Auxiliary Space: O(S*N)
Efficient approach : Using DP Tabulation method ( Iterative approach )
The approach to solve this problem is same but DP tabulation(bottom-up) method is better then Dp + memoization(top-down) because memoization method needs extra stack space of recursion calls.
Implementation :
C++
#include <bits/stdc++.h> using namespace std; // create DP to store previous computations int dp[2001][2001]; // Function to find the minimum number // of operations to make sum of A[] 0 void minOp(vector< int >& A, int N) { int sum = 0; // Find the sum of array for ( auto it : A) { sum += it; } if (sum % 2 == 0) { int target = sum / 2; // Initialize dp table for ( int i = 0; i <= N; i++) { dp[i][0] = 0; } for ( int j = 1; j <= target; j++) { dp[N][j] = 2001; } // Fill dp table in bottom-up manner for ( int i = N - 1; i >= 0; i--) { for ( int j = 1; j <= target; j++) { if (j >= A[i]) { dp[i][j] = min(dp[i + 1][j], dp[i + 1][j - A[i]] + 1); } else { dp[i][j] = dp[i + 1][j]; } } } // No solution exists if (dp[0][target] >= 2001) { cout << "-1" << endl; } // Otherwise else { cout << dp[0][target] << endl; } } // If sum is odd, no subset is possible else { cout << "-1" << endl; } } int main() { vector< int > A = { 2, 3, 1, 4 }; int N = A.size(); // Function Call minOp(A, N); return 0; } |
2
Time Complexity: O(S*N), where S is the sum of the given array.
Auxiliary Space: O(S*N)
Efficient approach : Space optimization
In previous approach the current value dp[i][j] is only depend upon the current and previous row values of DP. So to optimize the space complexity we use a single 1D array to store the computations.
Implementation:
C++
#include <bits/stdc++.h> using namespace std; // Function to find the minimum number // of operations to make sum of A[] 0 int minOp(vector< int >& A, int N) { int sum = 0; // Find the sum of array for ( auto it : A) { sum += it; } if (sum % 2 == 0) { int target = sum / 2; // Initialize dp table vector< int > dp(target + 1, 2001); dp[0] = 0; // Fill dp table in bottom-up manner for ( int i = 0; i < N; i++) { for ( int j = target; j >= A[i]; j--) { dp[j] = min(dp[j], dp[j - A[i]] + 1); } } // No solution exists if (dp[target] >= 2001) { cout << "-1" << endl; } // Otherwise else { cout << dp[target] << endl; } } // If sum is odd, no subset is possible else { cout << "-1" << endl; } } int main() { vector< int > A = { 2, 3, 1, 4 }; int N = A.size(); // Function Call minOp(A, N); return 0; } |
2
Time Complexity: O(S*N), where S is the sum of the given array.
Auxiliary Space: O(target), where target is S/2
Please Login to comment...