生成强大团队的最佳算法

时间:2017-07-06 03:16:33

标签: java algorithm

我得到了一份0-100技能的球员名单以及拥有所有成员名单的球队名单。

现在我想让球员加入球队,这样球队的大小基本相同(+ -1差异就可以了),技能总和应该尽可能接近。

我目前的解决方案是一种简单的投票算法(团队投票选择圈内球员,成为下一个最佳球员):

public class Teamgenerator {
    public void calcTeams(){
        List<Team> teams = new ArrayList<>();
        teams.add(new Team("Team 1"));
        teams.add(new Team("Team 2"));

        List<Player> players = new ArrayList<>();
        players.add(new Player("Player 1",25));
        players.add(new Player("Player 2",50));
        players.add(new Player("Player 3",50));
        players.add(new Player("Player 4",75));

        int nextTeam = 0;
        while (players.size() > 0) {
            int bestPlayer = findBestPlayerIndex(players);
            teams.get(nextTeam).players.add(players.get(bestPlayer));
            players.remove(bestPlayer);

            if (nextTeam < teams.size() - 1) nextTeam++;
            else nextTeam = 0;
        }

        for(Team t:teams){
            System.out.println(t.getName()+":");
            for(Player p:t.players)
                System.out.println(p.getName()+", Skill "+p.getSkill());
        }
    }


    private int findBestPlayerIndex(List<Player> players) {
        //In my real programm i have to pick the skill of a more complex player object from a DB, 
        //depending on a specific competition,  which causes i really need this index finding
        int index = -1;
        int highestSkill=-1;
        for (int i = 0; i < players.size(); i++) {
            if (players.get(i).getSkill() > highestSkill) {
                highestSkill = players.get(i).getSkill();
                index = i;
            }
        }
        return index;
    }
}

public class Team {
    private String name;
    public ArrayList<Player> players=new ArrayList<>();

    public Team(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class Player {
    private String name;
    private int skill=50; //From 0-100

    public Player(String name, int skill) {
        this.name = name;
        this.skill = skill;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getSkill() {
        return skill;
    }

    public void setSkill(int skill) {
        this.skill = skill;
    }   
}

问题在于,不是最平均的团队,控制台输出是:

第1组: 球员4,技能75; 球员3,技能50

第2组: 玩家2,技能50; 球员1,技能25

但如果球队是4 + 1和3 + 2球员会更公平。 你知道更公平的算法吗?谢谢你的帮助!

1 个答案:

答案 0 :(得分:2)

正如YouTube - The Fairest Sharing Sequence Ever - Standup Maths所示,Thue-Morse Sequence可能是您最大限度地减少首轮优势的最佳选择。

百科:

  

在数学中,Thue-Morse序列或Prouhet-Thue-Morse序列是通过从0开始并连续附加到目前为止获得的序列的布尔补码而得到的二进制序列(0和1的无限序列) 。该过程的前几个步骤产生字符串0然后01,0110,01101001,0110100110010110等,它们是Thue-Morse序列的前缀。 ...

Intro Computer Science - Princeton

//Copyright © 2000–2016, Robert Sedgewick and Kevin Wayne. 
public class ThueMorse { 
   public static void main(String[] args) { 
        int n = Integer.parseInt(args[0]);
        String thue   = "0";
        String morse  = "1";

        for (int i = 1; i <= n; i++) {
            String t = thue;             // save away values
            String m = morse;
            thue  += m;
            morse += t;
        }
        System.out.println(thue);
    }
}

Python答案移植,获得SO版权许可版本:

public static int whoseTurn(int turnCount){
    return Integer.bitCount(turnCount) % 2;
}

使用此转弯顺序,基于技能等级的排序列表应该给予更公平的团队,并满足你在+ -1成员范围内的约束。

通过生成前105位数来验证online encyclopedia of integer sequences (A010060)

import java.util.stream.IntStream;

public class NodeStack {

public static int whoseTurn(int turnCount){
    return Integer.bitCount(turnCount) % 2;
}

public static void main(String[] args) {
    System.out.print("OEIS: ");
    IntStream.range(0,105).map(NodeStack::whoseTurn).forEach(i->System.out.print(i+", "));
    String result = IntStream.range(0,105).map(NodeStack::whoseTurn).collect(StringBuilder::new,(sb,i)->sb.append(i), StringBuilder::append).toString();
    System.out.println();
    IntStream.range(1,105).forEach(
            (i)-> System.out.println(i+"# "+result.substring(0,i)+ " : " +diff(result.substring(0,i)))
    );
}

public static int diff(String s){
    int zero = 0;
    int one = 0;
    for (char c:s.toCharArray()){
        if (c=='0')zero++;
        if (c=='1')one++;
    }
    return zero-one;
}

}