好的,我有这个包含playerID和玩家averageScore的树形图。我想把它分成另外两张地图,这样每支队伍都有一定数量的玩家,整体玩家得分大致相同(偏差约为+/- 2)
private TreeMap<Integer, Double> teamScoreMap = new TreeMap<>();
private TreeMap<Integer, Double> team1 = new TreeMap<>();
private TreeMap<Integer, Double> team2 = new TreeMap<>();
public void createTeam()
{
teamScoreMap.put(001, 5.0);
teamScoreMap.put(002, 8.4);
teamScoreMap.put(003, 2.1);
teamScoreMap.put(004, 6.5);
teamScoreMap.put(005, 4.5);
teamScoreMap.put(006, 3.2);
teamScoreMap.put(007, 9.8);
teamScoreMap.put(008, 7.6);
}
答案 0 :(得分:1)
试试这个
TreeMap<Integer,Double> teamScoreMap = new TreeMap<Integer, Integer>(bigMap);
int size = teamScoreMap.size();
SortedMap<Integer, Double> team1 = teamScoreMap .subMap(0, size/2);
SortedMap<Integer, Double> team2 = teamScoreMap .subMap((size/2)+1,size);
没有理由实际投射到TreeMap,因为它没有提供任何与SortedMap相关的功能。
答案 1 :(得分:1)
逻辑就在那里,你只需要完成代码就可以将每个团队添加到每个地图中。
制作所有可能的团队,将他们的平均值与之前的最佳平均值进行比较。如果差异低于前一个,则交换它们。
最后,你们两者之间的差异最大。
{false=[1=5.0, 4=6.5, 5=4.5, 8=7.6], true=[2=8.4, 3=2.1, 6=3.2, 7=9.8]}
// false = 23.6 in total true = 23.5 in total
// As you see, the difference between both is the minimum possible (0.1)
public class Test {
private Map<Integer, Double> tsm = new TreeMap<>();
private Map<Integer, Double> team1 = new TreeMap<>();
private Map<Integer, Double> team2 = new TreeMap<>();
public void splitTeams() {
double average = tsm.values()
.stream()
.mapToDouble(x->x)
.average()
.getAsDouble();
int[] bestTeam = new int[4];
double bestAverage = 10;
double tmp;
for (int i = 1 ; i <= 8 ; i++) {
for (int j = 1 ; j <= 8 ; j++) {
for (int k = 1 ; k <= 8 ; k++) {
for (int l = 1 ; l <= 8 ; l++) {
if (Stream.of(i, j, k, l).distinct().count() == 4) {
tmp = Stream.of(tsm.get(i), tsm.get(j), tsm.get(k), tsm.get(l))
.mapToDouble(x -> x)
.average()
.getAsDouble();
if (Math.abs(average - tmp) < bestAverage) {
bestTeam[0] = i;
bestTeam[1] = j;
bestTeam[2] = k;
bestTeam[3] = l;
bestAverage = Math.abs(average - tmp);
}
}
}
}
}
}
List<Integer> team1 = Arrays.stream(bestTeam).boxed().collect(Collectors.toList());
Map<Boolean, List<Entry<Integer, Double>>> both = tsm.entrySet()
.stream()
.collect(Collectors.partitioningBy(e -> team1.contains(e.getKey())));
System.out.println(both);
}
public void createTeam() {
tsm.put(1, 5.0);
tsm.put(2, 8.4);
tsm.put(3, 2.1);
tsm.put(4, 6.5);
tsm.put(5, 4.5);
tsm.put(6, 3.2);
tsm.put(7, 9.8);
tsm.put(8, 7.6);
}
public static void main(String[] args) {
Test t = new Test();
t.createTeam();
t.splitTeams();
System.out.println();
}
}
答案 2 :(得分:0)
answer by Yassin Hajaj显示了计算此特定情况的最佳结果的一种方法。更一般地说,您要解决的是subset sum problem的特殊实例,并且存在相关问题 - 例如divide an array into two sets with minimal difference
基本上没有找到最佳解决方案的有效方法。
计算最优解的蛮力方法是计算一半元素的所有可能的选择,计算它们的总和,并找到与所需总和偏差最小的总和。
然而,在许多情况下,人们对 最佳解决方案不感兴趣,而只是在“好”解决方案中。这可以通过贪婪的方法来实现:首先,按降序对分数进行排序。然后,浏览团队成员列表,并将每个成员分配给当前具有较低分数的团队。
这两种方法都是在这里实现的,例如:
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);
}
}
// From https://github.com/javagl/Combinatorics/blob/master/src/main/
// java/de/javagl/utils/math/combinatorics/CombinationIterable.java
class ChoiceIterable<T> implements Iterable<List<T>>
{
private final List<T> input;
private final int sampleSize;
private final long numElements;
public ChoiceIterable(int sampleSize, List<T> input)
{
this.sampleSize = sampleSize;
this.input = input;
BigInteger nf = factorial(input.size());
BigInteger kf = factorial(sampleSize);
BigInteger nmkf = factorial(input.size() - sampleSize);
BigInteger divisor = kf.multiply(nmkf);
BigInteger result = nf.divide(divisor);
numElements = result.longValue();
}
public static BigInteger factorial(int n)
{
BigInteger f = BigInteger.ONE;
for (int i = 2; i <= n; i++)
{
f = f.multiply(BigInteger.valueOf(i));
}
return f;
}
@Override
public Iterator<List<T>> iterator()
{
return new Iterator<List<T>>()
{
private int current = 0;
private final int chosen[] = new int[sampleSize];
// Initialization of first choice
{
for (int i = 0; i < sampleSize; i++)
{
chosen[i] = i;
}
}
@Override
public boolean hasNext()
{
return current < numElements;
}
@Override
public List<T> next()
{
if (!hasNext())
{
throw new NoSuchElementException("No more elements");
}
List<T> result = new ArrayList<T>(sampleSize);
for (int i = 0; i < sampleSize; i++)
{
result.add(input.get(chosen[i]));
}
current++;
if (current < numElements)
{
increase(sampleSize - 1, input.size() - 1);
}
return result;
}
private void increase(int n, int max)
{
if (chosen[n] < max)
{
chosen[n]++;
for (int i = n + 1; i < sampleSize; i++)
{
chosen[i] = chosen[i - 1] + 1;
}
}
else
{
increase(n - 1, max - 1);
}
}
@Override
public void remove()
{
throw new UnsupportedOperationException(
"May not remove elements from a choice");
}
};
}
}
(用于计算选择的类取自here)
输出如下:
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
显示贪婪的结果不是最佳结果,但在这种情况下仍然相当不错。