Математическое решение для разделения X команд на 3 команды в день - PullRequest
1 голос
/ 19 марта 2019

Я пытаюсь разделить X количество команд на «игровые дни», которые состоят из 3 команд в день

Существует более одного решения для 15 команд.

Каков наилучший подход, чтобы найти все возможные матчи / планы матчей для команды 9-21? Количество команд 11, 14, 17 и 20 также вызывает проблемы, потому что total_matches / 3 = "должен быть четным / целым" enter image description here enter image description here enter image description here enter image description here

15 Teams // 105 Total Matches // 35 Total Days
D1 = 1:2  1:3  2:3
D2 = 2:4  2:5  4:5
D3 = 3:4  3:6  4:6
D4 = 4:1  4:7  1:7
D5 = 5:1  5:6  1:6
D6 = 6:2  6:7  2:7
7 = 7:3  7:5  3:5
8 = 8:1  8:9  1:9
9 = 9:2  9:10  2:10
10 = 10:1  10:11  1:11
11 = 11:2  11:8  2:8
12 = 12:1  12:13  1:13
13 = 13:2  13:14  2:14
14 = 14:1  14:15  1:15
15 = 2:12  2:15  12:15
16 = 3:8  3:10  8:10
17 = 3:9  3:11  9:11
18 = 3:12  3:14  12:14
19 = 4:8  4:12  8:12
20 = 5:8  5:13  8:13
21 = 6:8  6:14  8:14
22 = 7:8  7:15  8:15
23 = 9:4  9:13  4:13
24 = 9:5  9:12  5:12
25 = 10:4  10:14  4:14
26 = 11:4  11:15  4:15
27 = 12:6  12:10  6:10
28 = 13:3  13:15  3:15
29 = 14:5  14:11  5:11
30 = 5:10  5:15  10:15
D31 = 6:9  6:15  9:15
D32 = 6:11  6:13  11:13
D33 = 7:9  7:14  9:14
D34 = 7:10  7:13  10:13
D35 = 7:11  7:12  11:12

Ответы [ 2 ]

2 голосов
/ 19 марта 2019

(Python) Следующее выбирает следующие три команды для группирования в день на основе тех команд, которые до сих пор играли меньше всего игр и дает идеальное решение для случая с 9 командами:

    from itertools import combinations
    from string import ascii_uppercase

    TEAMCOUNT = 9

    teams = ascii_uppercase[:TEAMCOUNT]     # Just use uppercase letters for teams
    # All needed 2-team games 
    games = {''.join(two_teams) for two_teams in combinations(teams, 2)}
    # All possible 3-team days and the 2-team matches they map to
    triples = {x + y + z: {x+y, x+z, y+z}
               for x, y, z in combinations(teams, 3) }

    print('Teams:', teams)
    n = 0
    while games and triples:
        # Weighting based on number of games left to play
        weight = {t: sum(t in g for g in games) for t in teams}
        to_play = {t1+t2: min([weight[t1], weight[t2]]) for t1, t2 in games}
        # Choose teams that haven't played much next
        _, chosen_triple = max((sum(to_play[m] for m in matches if m in games), 
                                day)
                               for day, matches in triples.items())
        n += 1
        print(f"  Day{n}: {chosen_triple} Games: ", 
              ' '.join(sorted(m for m in triples[chosen_triple] if m in games)))
        games -= triples[chosen_triple]  # These games are played
        del triples[chosen_triple]       # This day triple used

    if games:
        print(" After those days, the following games remain to be played:", ' '.join(sorted(games)))
    else:
        print(" All games played!")

Выход для 9 команд:

Teams: ABCDEFGHI
  Day1: GHI Games:  GH GI HI
  Day2: DEF Games:  DE DF EF
  Day3: ABC Games:  AB AC BC
  Day4: CFI Games:  CF CI FI
  Day5: BEH Games:  BE BH EH
  Day6: ADG Games:  AD AG DG
  Day7: CEG Games:  CE CG EG
  Day8: BDI Games:  BD BI DI
  Day9: AFH Games:  AF AH FH
  Day10: CDH Games:  CD CH DH
  Day11: BFG Games:  BF BG FG
  Day12: AEI Games:  AE AI EI
 All games played!
1 голос
/ 19 марта 2019

Количество возможных комбинаций / матчей команд можно математически описать как Треугольное число .

Например, при наличии 9 команд число матчей равно 36. Sum k-1 from 1 to 9

Обратите внимание, что это число делится только на 3, когда k или k-1 делится на 3. С 5 командами вы получите 10 возможных игр.Ваша последняя неделя будет иметь только 1 игру, или вы можете структурировать ее по-разному.

Если вы хотите записать комбинации матчей, вы можете перечислить их, повторив количество команд дважды.Вот пример кода Java. Вы можете запустить его в онлайн-компиляторе Java.

    public class MyClass {

        public static void main(String args[]) {
            int TEAMS = 10; //Number of teams
            int combos = 0;

            for(int i = 1; i <= TEAMS-1; i++){
                for(int j = i+1; j <= TEAMS; j++){
                    System.out.println("Team " + i + " plays Team " + j);
                    combos ++;
                }
            }

            System.out.println("There is " + combos + " possible matches");
        }
    }

Нам нужна не просто каждая комбинация из двух команд.Мы хотим посмотреть на комбинации из 3 команд.Математически нам нужна комбинация .

Мы можем переписать наше Треугольное число, когда n выберет k.Наш предыдущий пример выглядит так:

9 choose 2

Каждую неделю, которую мы выбираем, играют 3 команды.Общее количество возможных дневных комбинаций - n выберите 3. В нашем примере с 9 командами.

9 choose 3

У нас есть 84 возможных дневных комбинации.Многие из этих дней имеют перекрывающиеся игры.Например, если у нас команды 1, 2 и 3 играют один день, то мы не хотим другого дня с командами 1,2 и 4, потому что тогда 1 и 2 играют 2 игры друг против друга.Решением для этого может быть игнорирование дублированных игр.

Я хочу отметить, что идеального решения не существует.Для большинства команд не существует решения, в котором каждый день 3 команды могут играть вместе, которые еще не играли.Например, когда у нас 4 команды, наши игры: 1-2, 1-3, 1-4, 2-3, 2-4, 3-4.Если мы взяли 3 из этих команд в первый день (1-2, 1-3, 2-3), то во второй день мы не получим идеальную комбинацию (1-4, 2-4, 3-4).

Независимо от того, как вы разбили его, вы можете сортировать по лучшим комбинациям, но в итоге у вас будет множество случайных игр.

Я создал код ниже, чтобы посмотретьв любой возможной комбинации дней и распечатывать дни, которые не дублируются.

    public class MyClass {

        public static void main(String args[]) {
            int TEAMS = 9; //Number of teams

            //Keep track of each game combination used
            boolean gamesPlayed[][] = new boolean[TEAMS+1][TEAMS+1];

            int day = 1;
            for(int i = 1; i <= TEAMS-2; i++){
                for(int j = i+1; j <= TEAMS-1; j++){
                    for(int k = TEAMS; k >= j+1; k--){

                        if(!gamesPlayed[i][j] && !gamesPlayed[i][k] && !gamesPlayed[j][k] )
                        {
                            System.out.println("Day "+ day++ + " Teams " + i + ", " + j + " & " + k + " Play");
                            gamesPlayed[i][j] = true;
                            gamesPlayed[i][k] = true;
                            gamesPlayed[j][k] = true;
                        }
                    }
                }
            }


            System.out.println("\nLeftover games");
            for(int i = 1; i <= TEAMS-1; i++){
                for(int j = i+1; j <= TEAMS; j++){
                    if(! gamesPlayed[i][j])
                        System.out.println(" Team " + i + " plays Team " + j);
                }
            }



        }
    }
...