如何为N队分成N / 2对产生所有可能的X组对决?

时间:2018-04-18 03:34:41

标签: python combinations permutation itertools schedule

我不确定如何说出这个问题...任何建议或编辑都将不胜感激!

我正试图获得联赛赛程的所有可能性。我 8支球队 12周中相互比赛。每周有四个时段,其中一对队伍将参加比赛。

How to split a list into pairs in all possible ways为我提供了一个解决方案:

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)]

等等。似乎有105 = 15 * 7这样的对。

然而,这些并非所有对。由于我有四个小组可以玩的时间段,列表中这些对的顺序可以改变

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

我想最终拥有所有可能的12对4对比赛,其中没有球队将比其他球队多出2次

如果我要通过以下方式创建所有可能的时间表:

# 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))

效率非常低,需要很长时间才能运行。这种方法没有考虑到一支球队是否已经打了另外两支球队。

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

<button class="navbar-toggler navbar-ligh" ... \>

1 个答案:

答案 0 :(得分:0)

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

我做了一种递归方法,以某种树状方式列出所有可能性。

  • 坏消息:可能需要太长时间(写这篇文章时没有完成)。
  • 好消息:对于6支队伍和8周(以及<1s时间)看起来很好,所以也许你/任何人都可以回收一些想法。

这是:

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)))