数据结构和算法

DSA - 主页 DSA - 概述 DSA - 环境设置 DSA - 算法基础 DSA - 渐近分析

数据结构

DSA - 数据结构基础 DSA - 数据结构和类型 DSA - 数组数据结构

链接列表

DSA - 链接列表数据结构 DSA - 双向链接列表数据结构 DSA - 循环链表数据结构

堆栈 &队列

DSA - 堆栈数据结构 DSA - 表达式解析 DSA - 队列数据结构

搜索算法

DSA - 搜索算法 DSA - 线性搜索算法 DSA - 二分搜索算法 DSA - 插值搜索 DSA - 跳跃搜索算法 DSA - 指数搜索 DSA - 斐波那契搜索 DSA - 子列表搜索 DSA - 哈希表

排序算法

DSA - 排序算法 DSA - 冒泡排序算法 DSA - 插入排序算法 DSA - 选择排序算法 DSA - 归并排序算法 DSA - 希尔排序算法 DSA - 堆排序 DSA - 桶排序算法 DSA - 计数排序算法 DSA - 基数排序算法 DSA - 快速排序算法

图形数据结构

DSA - 图形数据结构 DSA - 深度优先遍历 DSA - 广度优先遍历 DSA - 生成树

树数据结构

DSA - 树数据结构 DSA - 树遍历 DSA - 二叉搜索树 DSA - AVL 树 DSA - 红黑树 DSA - B树 DSA - B+ 树 DSA - 伸展树 DSA - 尝试 DSA - 堆数据结构

递归

DSA - 递归算法 DSA - 使用递归的汉诺塔 DSA - 使用递归的斐波那契数列

分而治之

DSA - 分而治之 DSA - 最大最小问题 DSA - 施特拉森矩阵乘法 DSA - Karatsuba 算法

贪婪算法

DSA - 贪婪算法 DSA - 旅行商问题(贪婪方法) DSA - Prim 最小生成树 DSA - Kruskal 最小生成树 DSA - Dijkstra 最短路径算法 DSA - 地图着色算法 DSA - 分数背包问题 DSA - 作业排序截止日期 DSA - 最佳合并模式算法

动态规划

DSA - 动态规划 DSA - 矩阵链乘法 DSA - Floyd Warshall 算法 DSA - 0-1 背包问题 DSA - 最长公共子序列算法 DSA - 旅行商问题(动态方法)

近似算法

DSA - 近似算法 DSA - 顶点覆盖算法 DSA - 集合覆盖问题 DSA - 旅行商问题(近似方法)

随机算法

DSA - 随机算法 DSA - 随机快速排序算法 DSA - Karger 最小割算法 DSA - Fisher-Yates 洗牌算法

DSA 有用资源

DSA - 问答 DSA - 快速指南 DSA - 有用资源 DSA - 讨论


Tug of War Problem

What is Tug of War Problem?

In the Tug of War problem, a set of integers is given and our task is to break them into two parts, such that the difference of the sum of two subsets is as minimal as possible. In other words, divide the set into two groups of nearly equal strength to participate in the tug-of-war game. When the size of set is even, it becomes easier to divide it into two parts. Doing this with odd numbers of items will be difficult. Thus, there are some constraints defined for dividing.

If the size of subset N is even, it can be divided into two parts using N/2, but for the odd value of N, the size of one subset must be (N-1)/2, and the size of another subset must be (N+1)/2.

Solving Tug of War using Backtracking Approach

Suppose the given set is of odd size −

Set = {23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4}

When we distribute the weights to make the difference minimum, then, the resulting subsets will be −

Left:  {45, -34, 12, 98, -1}
Right: {23, 0, -99, 4, 189, 4}
Tug of War

The following steps explain how backtracking approach is used to solve tug of war problem −

  • Start with creating an empty subset, say it as left.

  • Fill this empty subset with a required number of the elements from the original set. The required number of elements depends on the size of original set. If the size is odd, the subset should be filled with (N-1)/2 elements and if the size is even, the size of subset should be N/2.

  • Check whether the difference of filled elements follows the given constraints or not. If it follows mark it as a part of the solution.

  • If the difference is not minimum, try other combinations and update the existing solution.

  • Once the first subset is filled, the remaining elements will automatically become part of the second subset.

Example

In the following example, we will practically demonstrate how to solve the tug of war problem.

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>
#include <math.h>
void tgOfWarSoln(int* weight, int n, bool curr[], int select, bool sol[], int *diff, int sum, int total, int pos) {
   //when the pos is covered all weights    
   if (pos == n)     
      return;
    //left elements must be bigger than required result      
   if ((n/2 - select) > (n - pos))   
      return;
   tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos+1);
   select++;
   total += weight[pos];
   //add current element to the solution
   curr[pos] = true;      
   //when solution is formed
   if (select == n/2) {       
      //check whether it is better solution or not
      if (abs(sum/2 - total) < *diff) {     
         *diff = abs(sum/2 - total);
         for (int i = 0; i<n; i++)
            sol[i] = curr[i];
      }
   } else {
      tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos+1);
   }
   //when not properly done, remove current element
   curr[pos] = false;   
}
void checkSolution(int *arr, int n) {
   bool* curr = (bool*)malloc(n*sizeof(bool));
   bool* soln = (bool*)malloc(n*sizeof(bool));
   //set minimum difference to infinity initially
   int diff = INT_MAX;       
   int sum = 0;
   for (int i=0; i<n; i++) {
      //find the sum of all elements
      sum += arr[i];                  
      //make all elements as false
      curr[i] =  soln[i] = false;     
   }
   tgOfWarSoln(arr, n, curr, 0, soln, &diff, sum, 0, 0);
   printf("Left: ");
   for (int i=0; i<n; i++)
      if (soln[i] == true)
         printf("%d ", arr[i]);
   printf("
Right: ");
   for (int i=0; i<n; i++)
      if (soln[i] == false)
         printf("%d ", arr[i]);
   printf("
");
   free(curr);
   free(soln);
}
int main() {
   int weight[] = {23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4};
   int n = 11;
   checkSolution(weight, n);
   return 0;
}
#include <iostream>
#include <cmath>
#include <climits>
using namespace std;
void tgOfWarSoln(int* weight, int n, bool curr[], int select, bool sol[], int &diff, int sum, int total, int pos) {
   //when the pos is covered all weights    
   if (pos == n)     
      return;
    //left elements must be bigger than required result      
   if ((n/2 - select) > (n - pos))   
      return;
   tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos+1);
   select++;
   total += weight[pos];
   //add current element to the solution
   curr[pos] = true;      
   //when solution is formed
   if (select == n/2) {       
      //check whether it is better solution or not
      if (abs(sum/2 - total) < diff) {     
         diff = abs(sum/2 - total);
         for (int i = 0; i<n; i++)
            sol[i] = curr[i];
      }
   } else {
      tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos+1);
   }
   //when not properly done, remove current element
   curr[pos] = false;   
}
void checkSolution(int *arr, int n) {
   bool* curr = new bool[n];
   bool* soln = new bool[n];
   //set minimum difference to infinity initially
   int diff = INT_MAX;       
   int sum = 0;
   for (int i=0; i<n; i++) {
      //find the sum of all elements
      sum += arr[i];                  
      //make all elements as false
      curr[i] =  soln[i] = false;     
   }
   tgOfWarSoln(arr, n, curr, 0, soln, diff, sum, 0, 0);
   cout << "Left: ";
   for (int i=0; i<n; i++)
      if (soln[i] == true)
         cout << arr[i] << " ";
   cout << endl << "Right: ";
   for (int i=0; i<n; i++)
      if (soln[i] == false)
         cout << arr[i] << " ";
}
int main() {
   int weight[] = {23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4};
   int n = 11;
   checkSolution(weight, n);
}
public class Main {
   static void tgOfWarSoln(int[] weight, int n, boolean[] curr, int select, boolean[] sol, int[] diff, int sum, int total, int pos) {
      //when the pos is covered all weights
      if (pos == n)
         return;
      //left elements must be bigger than required result
      if ((n / 2 - select) > (n - pos))
         return;
      tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos + 1);
      select++;
      //add current element to the solution
      total += weight[pos];
      curr[pos] = true;
      //when solution is formed
      if (select == n / 2) {
         //check whether it is better solution or not
         if (Math.abs(sum / 2 - total) < diff[0]) {
            diff[0] = Math.abs(sum / 2 - total);
            for (int i = 0; i < n; i++)
               sol[i] = curr[i];
         }
      } else {
         tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos + 1);
      }
      //when not properly done, remove current element
      curr[pos] = false;
   }
   static void checkSolution(int[] arr, int n) {
      boolean[] curr = new boolean[n];
      boolean[] soln = new boolean[n];
      //set minimum difference to infinity initially
      int[] diff = {Integer.MAX_VALUE};
      int sum = 0;
      for (int i = 0; i < n; i++) {
         //find the sum of all elements
         sum += arr[i];
         //make all elements as false
         curr[i] = soln[i] = false;
      }
      tgOfWarSoln(arr, n, curr, 0, soln, diff, sum, 0, 0);
      System.out.print("Left: ");
      for (int i = 0; i < n; i++)
         if (soln[i] == true)
            System.out.print(arr[i] + " ");
      System.out.println();
      System.out.print("Right: ");
      for (int i = 0; i < n; i++)
         if (soln[i] == false)
            System.out.print(arr[i] + " ");
   }
   public static void main(String[] args) {
      int[] weight = {23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4};
      int n = 11;
      checkSolution(weight, n);
   }
}
def tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos):
    if pos == n:
        return
    
    if (n // 2 - select) > (n - pos):
        return
    
    tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos + 1)
    select += 1
    
    total += weight[pos]
    curr[pos] = True
    
    if select == n // 2:
        if abs(sum // 2 - total) < diff[0]:
            diff[0] = abs(sum // 2 - total)
            for i in range(n):
                sol[i] = curr[i]
    else:
        tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos + 1)
    
    curr[pos] = False

def checkSolution(arr, n):
    curr = [False] * n
    soln = [False] * n
    
    diff = [float('inf')]
    sum = 0
    for i in range(n):
        sum += arr[i]
        curr[i] = soln[i] = False
    
    tgOfWarSoln(arr, n, curr, 0, soln, diff, sum, 0, 0)
    print("Left: ", end="")
    for i in range(n):
        if soln[i] == True:
            print(arr[i], end=" ")
    print()
    print("Right: ", end="")
    for i in range(n):
        if soln[i] == False:
            print(arr[i], end=" ")

weight = [23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4]
n = 11
checkSolution(weight, n)

Output

Left: 45 -34 12 98 -1 
Right: 23 0 -99 4 189 4