Уникальные наборы комбинаций парных игр - PullRequest
0 голосов
/ 23 апреля 2020

Группа людей хочет сыграть в несколько игр вместе.
Матчи состоят из 2 команд, в каждой команде по 2 игрока, в общей сложности 4 уникальных игрока за матч.
Каждый хочет быть в команде со всеми остальными ровно один раз.
Каковы все комбинации уникальных матчей для N игроков, где каждая команда играет вместе только один раз?

Например, с игроками A, B, C и D. (N = 4)
Уникальными командами будут AB, A C, AD, B C, BD, CD.
Матчи могут быть AB + CD, AC + BD, AD + B C

Количество команд, указанное N игроками, может быть представлено суммой серии

(N-1)+(N-2)+(N-2)...(1) or (N-1)*(N)/2

Общее количество возможных матчей будет

* 1016. *

И общее количество неуникальных решений будет

(num_possible_matches choose num_teams/2)
or
((N choose 4) * ((4 choose 2) / 2)) choose ((N-1)*(N)/2)

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

Уникальные команды просты для вычисления

N = 5
people = [chr(i) for i in range(65,65+N)] # ['A', 'B', 'C', 'D', 'E'] 
teams = []

for i, person_one in enumerate(people):
  for person_two in people[i+1:]:
    teams.append((person_one, person_two))

# teams
# [('A', 'B'), ('A', 'C'), ('A', 'D'), ('A', 'E'), ('B', 'C'), ('B', 'D'), ('B', 'E'), ('C', 'D'), ('C', 'E'), ('D', 'E')]

Уникальные матчи также довольно просты

matches = []
for i, team1 in enumerate(teams):
  for team2 in teams[i:]:
    if len(set(team1).intersection(team2)) == 0:
      matches.append(((team1), (team2)))

# matches
# [(('A', 'B'), ('C', 'D')),
#  (('A', 'B'), ('C', 'E')),
#  (('A', 'B'), ('D', 'E')),
#  (('A', 'C'), ('B', 'D')),
#  (('A', 'C'), ('B', 'E')),
#  (('A', 'C'), ('D', 'E')),
#  (('A', 'D'), ('B', 'C')),
#  (('A', 'D'), ('B', 'E')),
#  (('A', 'D'), ('C', 'E')),
#  (('A', 'E'), ('B', 'C')),
#  (('A', 'E'), ('B', 'D')),
#  (('A', 'E'), ('C', 'D')),
#  (('B', 'C'), ('D', 'E')),
#  (('B', 'D'), ('C', 'E')),
#  (('B', 'E'), ('C', 'D'))]

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

Мой первоначальный подход заключался в создании графика, представляющего все возможные совпадения, с использованием команды

matches_graph
for team in teams:
  matches_graph[team] = []
  for matched_team in teams:
    if len(set(team).intersection(matched_team)) == 0:
      matches_graph[team].append(matched_team)

# matches_graph
# {('A', 'B'): [('C', 'D'), ('C', 'E'), ('D', 'E')],
#  ('A', 'C'): [('B', 'D'), ('B', 'E'), ('D', 'E')],
#  ('A', 'D'): [('B', 'C'), ('B', 'E'), ('C', 'E')],
#  ('A', 'E'): [('B', 'C'), ('B', 'D'), ('C', 'D')],
#  ('B', 'C'): [('A', 'D'), ('A', 'E'), ('D', 'E')],
#  ('B', 'D'): [('A', 'C'), ('A', 'E'), ('C', 'E')],
#  ('B', 'E'): [('A', 'C'), ('A', 'D'), ('C', 'D')],
#  ('C', 'D'): [('A', 'B'), ('A', 'E'), ('B', 'E')],
#  ('C', 'E'): [('A', 'B'), ('A', 'D'), ('B', 'D')],
#  ('D', 'E'): [('A', 'B'), ('A', 'C'), ('B', 'C')]}

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

def next_teams(visited=[]):
  to_return = []
  for team in matches_graph:
    if team not in visited:
      to_return.append(next_matches(team, visited+[team]))
  return to_return

def next_matches(choice, visited):
  to_return = []
  for team in matches_graph[choice]:
    if team not in visited:
      to_return.append([choice, [[team, next_teams(visited + [team])]]])
  return to_return

expanded_tree = next_teams()
# Gives us a list of trees in the format:
# tree = [value, [tree, tree, ...]]

Есть ли лучший способ вычислить набор комбинаций матчей, чтобы матч состоял из 4 уникальных игроков, и в наборе было (N-1)*(N)/4 комбинаций уникальных матчей?

...