Yassin Hajaj's answer shows one way to calculate the optimal result for this particular case. More generally, what you are trying to solve is a special instance of the problem of summing up a subset , and there are related questions - for example. divide the array into two sets with the minimum difference .
In principle, there is no effective way to find the optimal solution.
The brute force method for calculating the optimal solution is to calculate all possible options from half the elements, calculate their sum and find the sum that has the smallest deviation from the required amount.
However, in many cases the optimal solution is not interesting. but only in a βgoodβ solution. This can be achieved using a greedy approach: first, sort the grades in descending order. Then go to the list of team members and assign each of them to the team that currently has a lower score.
Both approaches are implemented here as an example:
import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.Set; import java.util.TreeMap; public class MapSplit { public static void main(String[] args) { TreeMap<Integer, Double> teamScoreMap = new TreeMap<Integer, Double>(); teamScoreMap.put(1, 5.0); teamScoreMap.put(2, 8.4); teamScoreMap.put(3, 2.1); teamScoreMap.put(4, 6.5); teamScoreMap.put(5, 4.5); teamScoreMap.put(6, 3.2); teamScoreMap.put(7, 9.8); teamScoreMap.put(8, 7.6); solveOptimal(teamScoreMap); solveGreedy(teamScoreMap); } private static void solveOptimal(Map<Integer, Double> teamScoreMap) { List<Entry<Integer, Double>> entries = new ArrayList<Entry<Integer, Double>>( teamScoreMap.entrySet()); double totalSum = computeSum(entries); ChoiceIterable<Entry<Integer, Double>> ci = new ChoiceIterable<Entry<Integer, Double>>( teamScoreMap.size() / 2, entries); List<Entry<Integer, Double>> bestTeam = null; double minError = Double.POSITIVE_INFINITY; for (List<Entry<Integer, Double>> team : ci) { double teamSum = computeSum(team); double error = Math.abs(teamSum - totalSum * 0.5); if (error < minError) { bestTeam = team; minError = error; } } Set<Entry<Integer, Double>> teamA = new LinkedHashSet<Entry<Integer, Double>>(bestTeam); Set<Entry<Integer, Double>> teamB = new LinkedHashSet<Entry<Integer, Double>>( teamScoreMap.entrySet()); teamB.removeAll(teamA); System.out.println("Optimal result:"); printResult(teamA, teamB); } private static void solveGreedy(Map<Integer, Double> teamScoreMap) { List<Entry<Integer, Double>> entries = new ArrayList<Entry<Integer, Double>>( teamScoreMap.entrySet()); Collections.sort(entries, (e0, e1) -> Double.compare(e1.getValue(), e0.getValue())); Set<Entry<Integer, Double>> teamA = new LinkedHashSet<Entry<Integer, Double>>(); double sumA = 0; Set<Entry<Integer, Double>> teamB = new LinkedHashSet<Entry<Integer, Double>>(); double sumB = 0; for (Entry<Integer, Double> entry : entries) { if (sumA < sumB) { teamA.add(entry); sumA += entry.getValue(); } else { teamB.add(entry); sumB += entry.getValue(); } } System.out.println("Greedy result:"); printResult(teamA, teamB); } private static void printResult( Collection<Entry<Integer, Double>> teamA, Collection<Entry<Integer, Double>> teamB) { System.out.println("Team A:"); for (Entry<Integer, Double> entry : teamA) { System.out.println(" " + entry); } System.out.println("Sum: " + computeSum(teamA)); System.out.println("Team B:"); for (Entry<Integer, Double> entry : teamB) { System.out.println(" " + entry); } System.out.println("Sum: " + computeSum(teamB)); } private static double computeSum( Collection<Entry<Integer, Double>> entries) { return entries.stream().map( e -> e.getValue()).reduce(0.0, (a,b) -> a+b); } }
(the class for calculating the selection is taken from here )
The output is as follows:
Optimal result: Team A: 1=5.0 4=6.5 5=4.5 8=7.6 Sum: 23.6 Team B: 2=8.4 3=2.1 6=3.2 7=9.8 Sum: 23.5 Greedy result: Team A: 2=8.4 8=7.6 1=5.0 3=2.1 Sum: 23.1 Team B: 7=9.8 4=6.5 5=4.5 6=3.2 Sum: 24.0
showing that the greedy result is not optimal, but in this case it is pretty good.