Open In App

Tug of War

Last Updated : 20 May, 2025
Summarize
Comments
Improve
Suggest changes
Share
Like Article
Like
Report

Given an array arr[] of size n, the task is to divide it into two subsets such that the absolute difference between the sum of elements in the two subsets.

  • If n is even, both subsets must have exactly n/2 elements.
  • If n is odd, one subset must have (n−1)/2 elements and the other must have (n+1)/2 elements.

Examples:

Input: arr[] = [3, 4, 5, -3, 100, 1, 89, 54, 23, 20]
Output:
3 5 -3 89 54
4 100 1 23 20
Explanation: The absolute difference between the two subsets is 0.

Input: arr[] = [23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4]
Output:
23 0 -99 4 189 4
45 -34 12 98 -1
Explanation: The absolute difference between the two subsets is 1, which is minimum.

Approach:

The idea is to use backtracking to explore all valid combinations of elements that can form two subsets of required sizes, and track the minimum absolute difference between their sums. A boolean array is used to keep track of which elements belong to the first subset, and at each step, the current element is either included in the first or second subset. 

Step by step approach:

  1. Start from the first index and recursively explore each element's inclusion in either of the two subsets.
  2. Track the count of elements added to the first subset to ensure size constraints are met.
  3. Maintain the current difference in subset sums while building the subsets.
  4. If the required number of elements is chosen, calculate the final difference and update the minimum if smaller.
  5. After recursion completes, use the final boolean array to separate the elements into two result subsets.
C++
#include <bits/stdc++.h>
using namespace std;

// Function that tries every possible solution by calling 
// itself recursively
void TOWUtil(const vector<int>& arr, vector<bool>& curr,
             int sel, vector<bool>& resSel, int& minDiff,
             int totalSum, int currSum, int pos) {

    int n = arr.size();

    // Check whether it is going out of bounds
    if (pos == n)
        return;

    // Check that the number of elements left are not 
    // less than the number of elements required to 
    // form the solution
    if ((n / 2 - sel) > (n - pos))
        return;

    // Consider the case when current element is not included
    TOWUtil(arr, curr, sel, resSel, minDiff, totalSum, currSum, pos + 1);

    // Add the current element to the solution
    sel++;
    currSum += arr[pos];
    curr[pos] = true;

    // Check if a solution is formed
    if (sel == n / 2) {
        
        // Check if this solution is better than the best so far
        int diff = abs(totalSum / 2 - currSum);
        if (diff < minDiff) {
            minDiff = diff;
            resSel = curr;
        }
    } 
    
    else {
        
        // Consider the case where current element is included
        TOWUtil(arr, curr, sel, resSel, minDiff, totalSum, currSum, pos + 1);
    }

    // Remove current element before returning to the caller
    curr[pos] = false;
}

// Function that returns the two subsets
pair<vector<int>, vector<int>> tugOfWar(const vector<int>& arr) {
    int n = arr.size();

    // Boolean array that contains inclusion/exclusion of an element
    vector<bool> curr(n, false);

    // Final solution mask
    vector<bool> resSel(n, false);

    int minDiff = INT_MAX;

    // Total sum of all elements
    int totalSum = accumulate(arr.begin(), arr.end(), 0);

    // Recursive solution
    TOWUtil(arr, curr, 0, resSel, minDiff, totalSum, 0, 0);

    // Prepare the two subsets
    vector<int> res1, res2;
    for (int i = 0; i < n; ++i) {
        if (resSel[i])
            res1.push_back(arr[i]);
        else
            res2.push_back(arr[i]);
    }

    return {res1, res2};
}

// Driver program to test above functions
int main() {
    vector<int> arr = {23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4};

    // Get the two subsets
    pair<vector<int>, vector<int>> res = tugOfWar(arr);

    // Print the subsets
    cout << "The first subset is: ";
    for (int x : res.first)
        cout << x << " ";

    cout << "\nThe second subset is: ";
    for (int x : res.second)
        cout << x << " ";

    return 0;
}
Java
// Function that tries every possible solution by calling 
// itself recursively
void TOWUtil(int[] arr, boolean[] curr,
             int sel, boolean[] resSel, int[] minDiff,
             int totalSum, int currSum, int pos) {

    int n = arr.length;

    // Check whether it is going out of bounds
    if (pos == n)
        return;

    // Check that the number of elements left are not 
    // less than the number of elements required to 
    // form the solution
    if ((n / 2 - sel) > (n - pos))
        return;

    // Consider the case when current element is not included
    TOWUtil(arr, curr, sel, resSel, minDiff, totalSum, currSum, pos + 1);

    // Add the current element to the solution
    sel++;
    currSum += arr[pos];
    curr[pos] = true;

    // Check if a solution is formed
    if (sel == n / 2) {
        
        // Check if this solution is better than the best so far
        int diff = Math.abs(totalSum / 2 - currSum);
        if (diff < minDiff[0]) {
            minDiff[0] = diff;
            resSel = curr.clone();
        }
    } 
    
    else {
        
        // Consider the case where current element is included
        TOWUtil(arr, curr, sel, resSel, minDiff, totalSum, currSum, pos + 1);
    }

    // Remove current element before returning to the caller
    curr[pos] = false;
}

// Function that returns the two subsets
public static Pair<List<Integer>, List<Integer>> tugOfWar(int[] arr) {
    int n = arr.length;

    // Boolean array that contains inclusion/exclusion of an element
    boolean[] curr = new boolean[n];

    // Final solution mask
    boolean[] resSel = new boolean[n];

    int[] minDiff = new int[]{Integer.MAX_VALUE};

    // Total sum of all elements
    int totalSum = 0;
    for (int num : arr) totalSum += num;

    // Recursive solution
    TOWUtil(arr, curr, 0, resSel, minDiff, totalSum, 0, 0);

    // Prepare the two subsets
    List<Integer> res1 = new ArrayList<>(), res2 = new ArrayList<>();
    for (int i = 0; i < n; ++i) {
        if (resSel[i])
            res1.add(arr[i]);
        else
            res2.add(arr[i]);
    }

    return new Pair<>(res1, res2);
}

// Driver program to test above functions
public static void main(String[] args) {
    int[] arr = {23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4};

    // Get the two subsets
    Pair<List<Integer>, List<Integer>> res = tugOfWar(arr);

    // Print the subsets
    System.out.print("The first subset is: ");
    for (int x : res.getKey())
        System.out.print(x + " ");

    System.out.print("\nThe second subset is: ");
    for (int x : res.getValue())
        System.out.print(x + " ");
}
Python
# Function that tries every possible solution by calling 
# itself recursively
def TOWUtil(arr, curr, sel, resSel, minDiff, totalSum, currSum, pos):
    n = len(arr)

    # Check whether it is going out of bounds
    if pos == n:
        return

    # Check that the number of elements left are not 
    # less than the number of elements required to 
    # form the solution
    if (n // 2 - sel) > (n - pos):
        return

    # Consider the case when current element is not included
    TOWUtil(arr, curr, sel, resSel, minDiff, totalSum, currSum, pos + 1)

    # Add the current element to the solution
    sel += 1
    currSum += arr[pos]
    curr[pos] = True

    # Check if a solution is formed
    if sel == n // 2:
        
        # Check if this solution is better than the best so far
        diff = abs(totalSum // 2 - currSum)
        if diff < minDiff:
            minDiff = diff
            resSel[:] = curr[:]
    else:
        
        # Consider the case where current element is included
        TOWUtil(arr, curr, sel, resSel, minDiff, totalSum, currSum, pos + 1)

    # Remove current element before returning to the caller
    curr[pos] = False

# Function that returns the two subsets
def tugOfWar(arr):
    n = len(arr)

    # Boolean array that contains inclusion/exclusion of an element
    curr = [False] * n

    # Final solution mask
    resSel = [False] * n

    minDiff = float('inf')

    # Total sum of all elements
    totalSum = sum(arr)

    # Recursive solution
    TOWUtil(arr, curr, 0, resSel, minDiff, totalSum, 0, 0)

    # Prepare the two subsets
    res1 = []
    res2 = []
    for i in range(n):
        if resSel[i]:
            res1.append(arr[i])
        else:
            res2.append(arr[i])

    return res1, res2

# Driver program to test above functions
if __name__ == '__main__':
    arr = [23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4]

    # Get the two subsets
    res = tugOfWar(arr)

    # Print the subsets
    print("The first subset is:", res[0])
    print("The second subset is:", res[1])
C#
// Function that tries every possible solution by calling 
// itself recursively
void TOWUtil(List<int> arr, bool[] curr,
             int sel, bool[] resSel, ref int minDiff,
             int totalSum, int currSum, int pos) {

    int n = arr.Count;

    // Check whether it is going out of bounds
    if (pos == n)
        return;

    // Check that the number of elements left are not 
    // less than the number of elements required to 
    // form the solution
    if ((n / 2 - sel) > (n - pos))
        return;

    // Consider the case when current element is not included
    TOWUtil(arr, curr, sel, resSel, ref minDiff, totalSum, currSum, pos + 1);

    // Add the current element to the solution
    sel++;
    currSum += arr[pos];
    curr[pos] = true;

    // Check if a solution is formed
    if (sel == n / 2) {
        
        // Check if this solution is better than the best so far
        int diff = Math.Abs(totalSum / 2 - currSum);
        if (diff < minDiff) {
            minDiff = diff;
            resSel = (bool[])curr.Clone();
        }
    } 
    
    else {
        
        // Consider the case where current element is included
        TOWUtil(arr, curr, sel, resSel, ref minDiff, totalSum, currSum, pos + 1);
    }

    // Remove current element before returning to the caller
    curr[pos] = false;
}

// Function that returns the two subsets
Tuple<List<int>, List<int>> tugOfWar(List<int> arr) {
    int n = arr.Count;

    // Boolean array that contains inclusion/exclusion of an element
    bool[] curr = new bool[n];

    // Final solution mask
    bool[] resSel = new bool[n];

    int minDiff = int.MaxValue;

    // Total sum of all elements
    int totalSum = arr.Sum();

    // Recursive solution
    TOWUtil(arr, curr, 0, resSel, ref minDiff, totalSum, 0, 0);

    // Prepare the two subsets
    List<int> res1 = new List<int>();
    List<int> res2 = new List<int>();
    for (int i = 0; i < n; ++i) {
        if (resSel[i])
            res1.Add(arr[i]);
        else
            res2.Add(arr[i]);
    }

    return Tuple.Create(res1, res2);
}

// Driver program to test above functions
void Main() {
    List<int> arr = new List<int> { 23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4 };

    // Get the two subsets
    var res = tugOfWar(arr);

    // Print the subsets
    Console.WriteLine("The first subset is: ");
    foreach (int x in res.Item1)
        Console.Write(x + " ");

    Console.WriteLine("\nThe second subset is: ");
    foreach (int x in res.Item2)
        Console.Write(x + " ");
}
JavaScript
// Function that tries every possible solution by calling 
// itself recursively
function TOWUtil(arr, curr, sel, resSel, minDiff, totalSum, currSum, pos) {
    const n = arr.length;

    // Check whether it is going out of bounds
    if (pos === n) {
        return;
    }

    // Check that the number of elements left are not 
    // less than the number of elements required to 
    // form the solution
    if ((n / 2 - sel) > (n - pos)) {
        return;
    }

    // Consider the case when current element is not included
    TOWUtil(arr, curr, sel, resSel, minDiff, totalSum, currSum, pos + 1);

    // Add the current element to the solution
    sel++;
    currSum += arr[pos];
    curr[pos] = true;

    // Check if a solution is formed
    if (sel === n / 2) {
        
        // Check if this solution is better than the best so far
        const diff = Math.abs(totalSum / 2 - currSum);
        if (diff < minDiff[0]) {
            minDiff[0] = diff;
            resSel.splice(0, resSel.length, ...curr);
        }
    } else {
        
        // Consider the case where current element is included
        TOWUtil(arr, curr, sel, resSel, minDiff, totalSum, currSum, pos + 1);
    }

    // Remove current element before returning to the caller
    curr[pos] = false;
}

// Function that returns the two subsets
function tugOfWar(arr) {
    const n = arr.length;

    // Boolean array that contains inclusion/exclusion of an element
    const curr = new Array(n).fill(false);

    // Final solution mask
    const resSel = new Array(n).fill(false);

    const minDiff = [Infinity];

    // Total sum of all elements
    const totalSum = arr.reduce((a, b) => a + b, 0);

    // Recursive solution
    TOWUtil(arr, curr, 0, resSel, minDiff, totalSum, 0, 0);

    // Prepare the two subsets
    const res1 = [];
    const res2 = [];
    for (let i = 0; i < n; i++) {
        if (resSel[i]) {
            res1.push(arr[i]);
        } else {
            res2.push(arr[i]);
        }
    }

    return [res1, res2];
}

// Driver program to test above functions
const arr = [23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4];

// Get the two subsets
const res = tugOfWar(arr);

// Print the subsets
console.log("The first subset is:", res[0]);
console.log("The second subset is:", res[1]);

Output
3 5 -3 89 54 
4 100 1 23 20 

Time Complexity: O(2^n)
Auxiliary Space: O(n)


Next Article
Article Tags :
Practice Tags :

Similar Reads