Формирование естественного графика для спортивной лиги - PullRequest
12 голосов
/ 06 мая 2011

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

Создать набор всех игр в сезоне легко, если команды список команд, которые будут выполнять следующие команды:

set((x, y) for x in teams for y in teams if x != y)

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

Ограничение состоит в том, что список игр должен быть сгруппирован в число раундов, где каждый раунд состоит из n / 2 игр (где n является количество команд), в которой каждая команда соединена с другой.

Чтобы расписание выглядело более естественным, две команды не должны сталкиваться с каждой другие дважды в последовательных раундах. То есть, если (a, b) играется в одном раунд, в игру (b, a) не следует играть в ext.

Также, насколько возможно, каждая команда должна играть в каждом следующем раунде, как команда гостей и другие раунды в качестве хозяев поля. Я так не думаю можно всегда выполнять это ограничение, поэтому лучше есть вещь. Например, одна команда не должна играть в 8 домашних игр и затем 8 выездных игр.

Вот что я получил сейчас. Основная проблема с алгоритмом заключается в том, что это часто застревает в цикле. Особенно когда количество команд 16 или больше. Это также очень неэффективно, потому что это основывается на использовании функции случайной выборки и надеется получить ее правильно:

from random import sample
def season_schedule_order(teams, pairs):
    n_games_per_round = len(teams) // 2
    last_pairs = set()
    while pairs:
        r_pairs = set(sample(pairs, n_games_per_round))
        # Check that each team is present once in the round.
        r_teams = set(x for (x, y) in r_pairs) | set(y for (x, y) in r_pairs)
        if r_teams != teams:
            continue
        # Check that two teams doesn't face each other again.
        rev_pairs = set((y, x) for (x, y) in r_pairs)
        if rev_pairs & last_pairs:
            continue
        pairs -= r_pairs
        for p in r_pairs:
            yield p
        last_pairs = r_pairs

teams = set(['aik', 'djurgarden', 'elfsborg', 'gais',
             'gefle', 'hacken', 'halmstad', 'helsingborg'])
pairs = set((x, y) for x in teams for y in teams if x != y)
for (ht, at) in season_schedule_order(teams, pairs):
    print '%-20s %-20s' % (ht, at)

Ответы [ 2 ]

2 голосов
/ 06 мая 2011

Я нашел метод здесь , который я немного адаптировал к этому:

def round_robin(units, sets = None):
    """ Generates a schedule of "fair" pairings from a list of units """
    count = len(units)
    sets = sets or (count - 1)
    half = count / 2
    for turn in range(sets):
        left = units[:half]
        right = units[count - half - 1 + 1:][::-1]
        pairings = zip(left, right)
        if turn % 2 == 1:
            pairings = [(y, x) for (x, y) in pairings]
        units.insert(1, units.pop())
        yield pairings

teams = ['a', 'b', 'c', 'd']
print list(round_robin(teams, sets = len(teams) * 2 - 2))

Теперь мне просто нужно превратить это в plpgsql. :)

0 голосов
/ 19 августа 2012
REQUIREMENTS for the BALANCED ROUND ROBIN algorithm
The requirements of the algorithm can be defined by these four rules:
 1) All versus all
 Each team must meet exactly once, and once only, the other teams in the division league. 
 If the division is composed of n teams, the championship takes place in the n-1 rounds.
2) Alternations HOME / AWAY rule
The sequence of alternations HOME / AWAY matches for every teams in the division league, should be retained if possible. 
For any team in the division league at most once in the sequence of consecutive matches HAHA, occurs the BREAK of the rhythm, i.e. HH or AA match in the two consecutive rounds.
3) The rule of the last slot number
The team with the highest slot number must always be positioned in the last row of the grid. 
For each subsequent iteration the highest slot number of grid alternates left and right position; left column (home) and right (away).
The system used to compose the league schedule is "counter-clockwise circuit." 
In the construction of matches in one round of the championship, a division with an even number of teams. 
If in a division is present odd number of teams, it will be inserted a BYE/Dummy team in the highest slot number of grid/ring.
4) HH and AA are non-terminal and not initial
 Cadence HH or AA must never happen at the beginning or at the end of the of matches for any team in the division.
 Corrective inversion RULE performs only once, in the bottom line in the RING, LeftRight redundant inversion flip-flop RULE, so we will never obtain in the last two rounds CC or FF.
Round Robin ALGORITHM
The algorithm that satisfies rule (1) is obtained with a simple algorithm Round Robin:
where every successive round is obtained applying to the slot numbers ring a   "counterclockwise" rotation.
To satisfy the rule (2) we must "improve", the simple round robin algorithm by performing balancing of Home and Away sequence. 
It is performed by applying several "counterclockwise" rotations in the slot numbers ring in order to obtain acceptable combinations of slot positions for the next round.

The number of rotations required in the ring is (n / 2 -1).
So we will get that in the two successive rounds, almost all the teams playing at home in the previous round, will play away from home in the next round.
DATA STRUCTURE
n_teams: (4,6,8,..,20)
n_rounds:  n_teams -1;

Ring - Circuit Ring - это такая структура данных, т. Е. Определенный тип последовательности, в которой выполняются и формально определяются алгоритмом: операция (против часовой стрелки) ROTATION среди элементов кольца и операция INSERT_LAST_TEAM, содержимое кольца определяет всесоответствует каждому конкретному раунду в расписании матчей. Ring.Length - четное число, равное n_teams. Подпоследовательность Left_ring: Подпоследовательность Ring с элементами от 1 до n / 2.Подпоследовательность Right_ring: Подпоследовательность кольца с элементами от n / 2 + 1 до n.Match [i] = Ring_element [i]: Ring_element [n - i + 1];где i = от 1 до n / 2 MATCH - это упорядоченная пара, состоящая из двух КОМАНД (Home_team: Away_team).1-й тур Дома: В гостях 01:07 02:06 03:05 04: 08

Next_Iteration is obtained by applying these rules:
a)   perform (n/2 – 1) times * ANTI CLOCKWISE ROTATIONs  
b)   all right column elements, below the last team, will be shifted upwards 
c)   INSERT_LAST_TEAM 
(Insert_Last_Element_into_ Ring_onLeft (n) or 
 Insert_Last_Element_into_Ring_onRight(n), alternatively)
d.1) Last Line LeftRight redundant swap RULE 
eventually have to swap elements in the last row once again
d.1) last team left/right - flip/flop



In the following example it will be explained how the Ring elements of 8 teams 
are gradually transformed in five steps, 
from from the SECOND ROUND into the THIRD ROUND.
If we start from from the SECOND ROUND:
05 :04
06 :03
07 :02
08 :01
a. After we perform THREE Anti-clockwise rotations, (n =8, 3 = 8/2 -1)
we will get the situation like this:
02 :01
03 :08
04 :07
05 :06
b. When we apply the LAST SLOT RULE: 
the right column elements (06,07) below last team (08) will be shifted upwards
02 :01
03
04 :07
05 :06
c. And now we will apply the LAST SLOT RULE-bottom right, 
we will get the situation which describes the THIRD ROUND: 
(08 must be moved to the bottom right position)
02 :01
03 :07
04 :06
05 :08
d.1 Now it will be checked if for this iteration number (i.e. round) 
depending on CODE SIX or ZERO Cadence, we eventually have to 
swap elements in the last row redundantly,
Left/Right swaping
d.2 And at the end we will apply the LAST TEAM SLOT ROULE
swap left & right elements, 
if in the previous iteration last team was positioned on the right, 
in this iteration it should be positioned on the left bottom position, 
so the last line elements will be swapped, else do nothing.
THIRD ROUND:
02 :01
03 :07
04 :06
05 :08

подробнее

Вот фрагмент кодав Perl.

...