【问题标题】:How to generate all possible X sets of matchups for N teams split into N/2 pairs?如何为分成 N/2 对的 N 支球队生成所有可能的 X 组比赛?
【发布时间】:2018-04-18 03:34:40
【问题描述】:

我不知道如何措辞这个问题...任何建议或编辑将不胜感激!

我正在尝试获取联赛日程的所有可能性。我有 8 支球队,他们正在互相对抗 12 周。每周有 四个时段,一对团队将在其中进行比赛。

How to split a list into pairs in all possible ways 给了我一个解决办法:

[(0, 1), (2, 3), (4, 5), (6, 7)]
[(0, 1), (2, 3), (4, 6), (5, 7)]
[(0, 1), (2, 3), (4, 7), (5, 6)]
...
[(0, 2), (1, 3), (4, 5), (6, 7)]
[(0, 2), (1, 3), (4, 6), (5, 7)]
[(0, 2), (1, 3), (4, 7), (5, 6)]

等等。好像有 105 = 15*7 这样的对。

但是,这些并不是所有的对。由于我有 4 个时间段可供球队参加比赛,因此这些对在列表中的顺序可以改变

Ex:
(0, 1) is the same as (1, 0) 
but
[(0, 1), (2, 3), (4, 5), (6, 7)]
is not the same as
[(2, 3), (0, 1), (4, 5), (6, 7)]

我希望最终拥有所有可能的 12 组这些 4 对比赛,其中 没有一支球队会与另一支球队交手超过 2 次​​strong>。

如果我要创建所有可能的时间表:

schedules = list(itertools.combinations(<all_possible_4-pair_matchups>, 12))

这将非常低效并且需要很长时间才能运行。这种方法不考虑一支球队是否曾与另一支球队交手超过两次。

到目前为止我有这个代码:

# Author: Abraham Glasser, abrahamglasser@gmail.com
#
# This program determines if there's a schedule where
# each team will play at a specific hour exactly 3 times
#
# 12 weeks
# 8 teams
# 4 hours per week

from pandas import *

teams = [i for i in range(8)]

twelve_weeks = [[[-1 for i in range(2)] for j in range(4)] for k in range(12)]

# table to count how many times a team 
# has played at a specific time slot
hour_count = [[0 for i in range(4)] for j in range(8)]

# table to count how many times two teams have played each other
game_count = [[0 for i in range(8)] for j in range(8)]
for i in range(8):
    # a team cannot play against itself
    game_count[i][i] = "X"


# function to update game count
def update_game_count():
    for week in twelve_weeks:
        for hour in week:
            if hour[0] == -1:
                pass
            else:
                game_count[hour[0]][hour[1]] += 1
                game_count[hour[1]][hour[0]] += 1

# function to update hour count
def update_hour_count():
    for week in twelve_weeks:
        for hour in range(4):
            pair = week[hour]
            for team in teams:
                if team in pair:
                    hour_count[team][hour] += 1

# solution from 
# https://stackoverflow.com/questions/5360220/how-to-split-a-list-into-pairs-in-all-possible-ways
def all_pairs(lst):
    if len(lst) < 2:
        yield lst
        return
    a = lst[0]
    for i in range(1,len(lst)):
        pair = (a,lst[i])
        for rest in all_pairs(lst[1:i]+lst[i+1:]):
            yield [pair] + rest


x = list(all_pairs([0, 1, 2, 3, 4, 5, 6, 7]))

# TAKES TOO LONG AND DOES NOT ACCOUNT
# FOR TEAMS PLAYING MORE THAN TWICE
#
# schedules = list(itertools.combinations(x, 12))

# pretty printing

print("\nThe twelve weeks:")
print(DataFrame(twelve_weeks))

print("\n The hour counts:")
print(DataFrame(hour_count))

print("\n The game counts:")
print(DataFrame(game_count))

【问题讨论】:

    标签: python combinations permutation itertools schedule


    【解决方案1】:

    您对解决方案的数量有估计吗? 如果这个数字太大,那么将无法列出所有这些配对。

    我采用递归方法以某种树状方式列出所有可能性。

    • 坏消息:可能需要很长时间(写这篇文章时没有完成)。
    • 好消息:6 个团队和 8 周(以及

    这里是:

    import itertools
    import numpy as np
    
    n = 6
    weeks = 8
    
    def all_pairs(lst):
      if len(lst) < 2:
        yield lst
        return
      a = lst[0]
      for i in range(1,len(lst)):
        pair = (a,lst[i])
        for rest in all_pairs(lst[1:i]+lst[i+1:]):
          yield [pair] + rest
    
    def recurse(so_far, rem_list, count):
      if len(so_far) == weeks: return [so_far]
    
      res = []
      for current in range(len(rem_list)):
        match = rem_list[current]
        new_count = count.copy()
        for pair in match:
          new_count[pair[0],pair[1]] += 1
          new_count[pair[1],pair[0]] += 1
        #set of pairs, whcih are not allowed any more
        forbidden = {(i,j) for i in range(n) for j in range(n) if new_count[i,j] == 2}
        #append current match, remove all now forbidden combinations
        res += recurse(so_far + [match], [entry for entry in rem_list[(current+1):] if set(entry) & forbidden == set([])], new_count)
      return res
    
    l = list(all_pairs(list(range(n))))
    foo = recurse([], l, np.zeros((n,n)))
    

    【讨论】:

    • 您可能希望删除 NumPy 导入行,以明确您实际上并未在答案中使用它。
    • 感谢您的回答。也许我应该澄清一下,一支球队将每周比赛一次。当我运行您的代码时,看起来 foo 是一个 465 x 8 矩阵。 105 对是 8 支球队 4 对的可能组合。应该有4个!这些中的每一个的排列,因此在特定的一周内有 2520 个可能的对决。由于有 12 周,这意味着可能的时间表数量为 2520 选择 12,这是一个 33 位数长的数字!然而,其中许多包括相互比赛超过两次的球队......
    • 我可能错了,可能的团队顺序是 8!,然后我们需要其中的 12 个,所以可能是 8 个!选择 12,这是一个 47 位数长的数字。 (这包括冗余,例如将 (1, 4) 和 (4, 1) 视为不同)
    猜你喜欢
    • 1970-01-01
    • 2020-09-21
    • 2021-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多