【问题标题】:Volleyball Player Combination排球运动员组合
【发布时间】:2013-07-21 02:50:05
【问题描述】:

一些背景:
在排球比赛中,球员们在台球中进行比赛以确定排名。团队是成对的玩家。比赛是一对球员对另一对球员。对于这个例子,假设只有一个球场可以进行比赛,当一名球员不比赛时,他们正在坐下/等待。池中的玩家人数将在 4 到 7 之间。如果池中有 8 名玩家,他们会将其分成 2 个 4 人池。

我想计算最少的比赛次数,以便每个玩家与其他玩家一起玩。

例如,一个 4 人池将有以下球队:

import itertools
players = [1,2,3,4]
teams = [t for t in itertools.combinations(players,2)]
print 'teams:'
for t in teams:
    print t

输出:

teams:
(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)

以及匹配的数量:

matches = []
for match in itertools.combinations(teams,2):
    # A player cannot be on both teams at the same time
    if set(match[0]) & set(match[1]) == set():
        matches.append(match)

for match in matches:
    print match

输出:

((1, 2), (3, 4))
((1, 3), (2, 4))
((1, 4), (2, 3))

这是正确的,但是当我将第 5 个玩家添加到池中时,此算法会中断:

((1, 2), (3, 4))
((1, 2), (3, 5))
((1, 2), (4, 5))
((1, 3), (2, 4))
((1, 3), (2, 5))
((1, 3), (4, 5))
((1, 4), (2, 3))
((1, 4), (2, 5))
((1, 4), (3, 5))
((1, 5), (2, 3))
((1, 5), (2, 4))
((1, 5), (3, 4))
((2, 3), (4, 5))
((2, 4), (3, 5))
((2, 5), (3, 4))

团队多次重复。

我试图保留一份参赛球队的名单,但该算法被证明是贪心的。我的意思是当它到达(1,5)队时,所有其他队[(2,3),(2,4),(3,4)]已经参加过比赛并且(1,5)永远不会玩。

我在寻找什么:

((1,2), (3,4)) (player 5 waits)
((1,3), (2,5)) (player 4 waits)
((1,4), (3,5)) (player 2 waits)
((1,5), (4,2)) (player 3 waits)
((2,3), (4,5)) (player 1 waits)

为每个池大小手动计算会更容易,还是可以在 python 中轻松完成?

感谢您的帮助!


编辑: 删除了 Python 标记。任何语言都可以,我可以将其转换为 Python。

【问题讨论】:

  • 你所说的“一起玩”是指“在同一个游戏中玩”、“在同一边玩”还是“玩对抗”?
  • @user2357112 - “一起玩”我的意思是在同一边玩。例如,球队 (1,2) 将只与 5 名球员池中的另一支球队比赛。预计他们不会与其他所有球队比赛。
  • 另外 - 它开始看起来像一个 6 人池,至少一个团队将一起玩两次。
  • 有人能解释为什么这会得到很多赞成吗?我发现它是一个没有信息的标题,而且粗体的问题甚至与 Python 无关。这是一个有趣的问题,但除非措辞不同,否则不属于这一类。
  • @Dualinity:Python中有示例代码,OP正在寻找Python中的解决方案。标签是正确的。至于赞成票,他们可能在那里,因为这是一个有趣的问题。

标签: algorithm combinations


【解决方案1】:

执行摘要:

  • 尽管它与 NP 完全最小集覆盖问题相似,但这个问题远非棘手。特别是 - 与最小集合覆盖完全不同 - 我们提前知道一个重要的最佳答案。

  • 答案是团队数除以 2(当团队 N 为奇数时加 1)。我们永远不会做得比这更好。

  • 由于问题的结构,有 许多 可接受的解决方案可以实现最佳答案。您可以使用基本的随机贪心算法偶然发现它们。随着 N 个团队越来越大,您的第一次随机尝试几乎总是成功的。

  • 即使对于大量团队,这种方法也很快(例如,对于 1000 个团队来说只需几秒钟)。

详情:

您可以使用 k 组合的公式来确定所需的团队数量,以便每个玩家都与其他玩家配对(k = 2)。

n_teams = n! / ( (n - k)! k! )

n     n_teams
--    --------
4     6
5     10
6     15
7     21
8     28
9     36
10    45
11    55      # n_teams always equals the sum of values in previous row

最少匹配数是多少?我认为它只是 n_teams 除以 2(有一些填充来处理奇数个团队)。

min_n_matches = (n_teams + (n_teams % 2)) / 2

对此我没有严格的证据,但直觉似乎是正确的。每次添加新玩家时,您都可以将其视为额外的约束:您刚刚添加了一名无法同时出现在给定比赛双方的玩家。同时,新玩家产生了一堆新的团队组合。这些新团队就像反约束:他们的存在使形成有效匹配变得更加容易。

从上面的公式和数据表可以看出,约束 (n) 以线性方式增长,但反约束 (n_teams) 增长得更快。

如果是这样,您就不需要智能算法来解决问题:最贪婪、最脑残的算法也能正常工作。随机匹配团队(但有效),如果您的第一次尝试失败,请再试一次。随着团队数量的增加,您很少会在第一次尝试时失败。

可能有更好的方法来实现这个想法,但这里有一个插图,它生成了球队和比赛,并证实了上面隐含的断言。

import sys
import itertools
import random

def main():
    maxN = int(sys.argv[1])
    for n in range(4, maxN + 1):
        run_scenario(n)

def run_scenario(n):
    # Takes n of players.
    # Generates matches and confirms our expectations.
    k = 2
    players = list(range(1, n + 1))
    teams   = list(set(t) for t in itertools.combinations(players, k))

    # Create the matches, and count how many attempts are needed.
    n_calls = 0
    matches = None
    while matches is None:
        matches = create_matches(teams)
        n_calls += 1

    # Print some info.
    print dict(
        n       = n,
        teams   = len(teams),
        matches = len(matches),
        n_calls = n_calls,
    )

    # Confirm expected N of matches and that all matches are valid.
    T = len(teams)
    assert len(matches) == (T + (T % 2)) / 2
    for t1, t2 in matches:
        assert t1 & t2 == set()

def create_matches(teams):
    # Get a shuffled copy of the list of teams.
    ts = list(teams)
    random.shuffle(ts)

    # Create the matches, greedily.
    matches = []
    while ts:
        # Grab the last team and the first valid opponent.
        t1 = ts.pop()
        t2 = get_opponent(t1, ts)
        # If we did not get a valid opponent and if there are still
        # teams remaining, the greedy matching failed.
        # Otherwise, we must be dealing with an odd N of teams.
        # In that case, pair up the last team with any valid opponent.
        if t2 is None:
            if ts: return None
            else:  t2 = get_opponent(t1, list(teams))
        matches.append((t1, t2))

    return matches

def get_opponent(t1, ts):
    # Takes a team and a list of teams.
    # Search list (from the end) until it finds a valid opponent.
    # Removes opponent from list and returns it.
    for i in xrange(len(ts) - 1, -1, -1):
        if not t1 & ts[i]:
            return ts.pop(i)
    return None

main()

输出样本。请注意调用次数如何很快趋向 1。

> python volleyball_matches.py 100
{'matches': 3, 'n_calls': 1, 'teams': 6, 'n': 4}
{'matches': 5, 'n_calls': 7, 'teams': 10, 'n': 5}
{'matches': 8, 'n_calls': 1, 'teams': 15, 'n': 6}
{'matches': 11, 'n_calls': 1, 'teams': 21, 'n': 7}
{'matches': 14, 'n_calls': 4, 'teams': 28, 'n': 8}
{'matches': 18, 'n_calls': 1, 'teams': 36, 'n': 9}
{'matches': 23, 'n_calls': 1, 'teams': 45, 'n': 10}
{'matches': 28, 'n_calls': 1, 'teams': 55, 'n': 11}
{'matches': 33, 'n_calls': 1, 'teams': 66, 'n': 12}
...
{'matches': 2186, 'n_calls': 1, 'teams': 4371, 'n': 94}
{'matches': 2233, 'n_calls': 1, 'teams': 4465, 'n': 95}
{'matches': 2280, 'n_calls': 1, 'teams': 4560, 'n': 96}
{'matches': 2328, 'n_calls': 1, 'teams': 4656, 'n': 97}
{'matches': 2377, 'n_calls': 1, 'teams': 4753, 'n': 98}
{'matches': 2426, 'n_calls': 1, 'teams': 4851, 'n': 99}
{'matches': 2475, 'n_calls': 1, 'teams': 4950, 'n': 100}

【讨论】:

  • 不是证明,但非常好。
  • 对手头问题的出色回答!
  • 也许我理解错了,但是当我尝试随机洗牌(见下文)时,调用次数肯定不会随着池大小的增加而减少。
【解决方案2】:

您可以将其表示为集合覆盖问题。有 4 名玩家,取所有(无序)玩家对的集合:

PP := {{0,1}, {0,2}, {0,3}, {1,2}, {1,3}, {2,3}}

可能的匹配是这些对中的无序对,这样双方的玩家就不会相同。在这里,可能的匹配是:

M := {{{0,1},{2,3}}, {{0,2},{1,3}}, {{0,3},{1,2}}}

你现在的问题是你想找到这个集合的最小子集,使得它的并集是所有玩家对的集合,PP。

这是the minimum set cover problem 的一个实例,它是NP 完全的。也许将集合限制为对会提供更简单的解决方案,但如果不是这样也不足为奇。

由于您仅限于较小的集合,因此仅通过蛮力解决它是可行的。

我们知道至少需要 ceil(N * (N-1) / 4) 匹配(因为有 N * (N-1) / 2 不同的配对,每场匹配最多可以覆盖 2 个新配对)。这给了我们一个算法。

import itertools

def mincover(n):
    pairs = set(map(tuple, itertools.combinations(range(n), 2)))
    matches = itertools.combinations(pairs, 2)
    matches = [m for m in matches if not(set(m[0]) & set(m[1]))]
    for subset_size in xrange((len(pairs) + 1) // 2, len(pairs) + 1):
        for subset in itertools.combinations(matches, subset_size):
            cover = set()
            for s in subset: cover |= set(s)
            if cover == pairs:
                return subset

for i in xrange(4, 8):
    print i, mincover(i)

这很慢,尤其是对于 6 和 7 名玩家。这可以通过不考虑不添加新玩家对的匹配的手动编码搜索以及使用对称性并始终包含{{0,1}, {2,3}} 来稍微改进。

【讨论】:

  • 这计算得非常快,直到 6 人池,但它已经在 7 人池上搅动了近一个小时。第 5 个玩家池的结果与我的不同,但仍然是正确的。 6 人池输出 8 场比赛,但一支球队一起比赛两次。我不确定这是否有任何问题。
  • 6 名球员有 15 对,每场比赛由两对组成。所以总会有一对可以一起玩两次。
  • 也许与最小集覆盖问题的类比使我们走上了一条过于困难的道路。在这个问题中,我们已经知道最好的结果。如果我们有 N 支球队(为了简单起见,假设 N 是偶数),硬限制的最小比赛数是 N/2(这是我们能做到的最好的)。我们所要做的就是在 N/2 场合法比赛中配对 N 支球队,我们就完成了。我认为这样的配对很容易贪婪地找到。
【解决方案3】:

我不知道 Python,但我忍不住在 Ruby 中尝试它。希望这将很容易地转换为 Python。如果你不了解 Ruby,我很乐意解释这里发生了什么:

num_players = gets.to_i
players = (1..num_players).to_a
teams = players.combination(2).to_a

def shuffle_teams( teams, players )
  shuffled_teams = teams.shuffle
  x = 0
  while x < shuffled_teams.length
    if shuffled_teams[x] - shuffled_teams[x + 1] == shuffled_teams[x]
      x += 2
    else
      return shuffle_teams( teams, players )
    end
  end
  x = 0
  while x < shuffled_teams.length
    team_1 = shuffled_teams[x]
    team_2 = shuffled_teams[x + 1]
    waiting = players.select do |player|
      ![team_1, team_2].flatten.include?(player)
    end
    print "(#{team_1}, #{team_2}), waiting: #{waiting}\n"
    x += 2
  end
end

shuffle_teams( teams, players )

这会为 4 个玩家生成正确的输出:

([3, 4], [1, 2]), waiting: []
([1, 3], [2, 4]), waiting: []
([2, 3], [1, 4]), waiting: []

对于 5 名玩家:

([2, 4], [1, 3]), waiting: [5]
([1, 5], [3, 4]), waiting: [2]
([1, 4], [2, 5]), waiting: [3]
([3, 5], [1, 2]), waiting: [4]
([2, 3], [4, 5]), waiting: [1]

但是,它不适用于 6 或 7 名玩家,因为每个玩家都会产生奇数个组合。这个问题在现实生活中是如何处理的?不知何故,一支球队将不得不打两次。

编辑:此脚本现在将通过复制其中一个团队来处理 6 或 7 个玩家池。它应该很容易在 Python 中复制,因为它只依赖于对团队数组进行洗牌,直到他们进入适当的顺序。起初,我觉得我用这种方法有点作弊,但鉴于 Anonymous 解释这是一个 NP 完全问题(假设我正确理解这意味着什么:-),这可能是解决问题的最佳方法小池(它会因池大于 9 左右而爆炸,具体取决于您的系统,但幸运的是,这超出了我们的场景范围)。再加上随机排序的优点是没有人情味,如果玩家因为必须玩两次而没有第二次得分而感到不安,这可能会派上用场!这是脚本:

num_players = gets.to_i
players = (1..num_players).to_a
teams = players.combination(2).to_a

def shuffle_teams( teams, players )
  shuffled_teams = teams.shuffle
  x = 0
  while x < shuffled_teams.length
    if !shuffled_teams[x + 1]
      shuffled_teams[x + 1] = shuffled_teams.find do |team|
        shuffled_teams[x] - team == shuffled_teams[x]
      end
    end
    if shuffled_teams[x] - shuffled_teams[x + 1] == shuffled_teams[x]
      x += 2
    else
      return shuffle_teams( teams, players )
    end   
  end
  x = 0
  while x < shuffled_teams.length
    team_1 = shuffled_teams[x]
    team_2 = shuffled_teams[x + 1]
    waiting = players.select do |player|
      ![team_1, team_2].flatten.include?(player)
    end
    print "(#{team_1}, #{team_2}), waiting: #{waiting}\n"
    x += 2
  end
end

shuffle_teams( teams, players )

这是输出,带有时间:

4
([1, 4], [2, 3]), waiting: []
([1, 2], [3, 4]), waiting: []
([2, 4], [1, 3]), waiting: []

real    0m0.293s
user    0m0.035s
sys 0m0.015s

5
([4, 5], [1, 2]), waiting: [3]
([1, 4], [2, 3]), waiting: [5]
([2, 5], [1, 3]), waiting: [4]
([2, 4], [3, 5]), waiting: [1]
([3, 4], [1, 5]), waiting: [2]

real    0m0.346s
user    0m0.040s
sys 0m0.010s

6
([3, 4], [1, 2]), waiting: [5, 6]
([3, 5], [2, 4]), waiting: [1, 6]
([3, 6], [1, 5]), waiting: [2, 4]
([1, 6], [2, 5]), waiting: [3, 4]
([2, 3], [4, 6]), waiting: [1, 5]
([2, 6], [4, 5]), waiting: [1, 3]
([5, 6], [1, 4]), waiting: [2, 3]
([1, 3], [2, 4]), waiting: [5, 6]

real    0m0.348s
user    0m0.035s
sys 0m0.020s

7
([1, 6], [4, 5]), waiting: [2, 3, 7]
([2, 6], [1, 4]), waiting: [3, 5, 7]
([2, 7], [1, 3]), waiting: [4, 5, 6]
([3, 4], [2, 5]), waiting: [1, 6, 7]
([3, 5], [2, 4]), waiting: [1, 6, 7]
([1, 7], [5, 6]), waiting: [2, 3, 4]
([6, 7], [1, 5]), waiting: [2, 3, 4]
([3, 6], [4, 7]), waiting: [1, 2, 5]
([1, 2], [5, 7]), waiting: [3, 4, 6]
([3, 7], [4, 6]), waiting: [1, 2, 5]
([2, 3], [1, 6]), waiting: [4, 5, 7]

real    0m0.332s
user    0m0.050s
sys 0m0.010s

【讨论】:

  • 下次打球的时候我得拿排球表看看他们是怎么做到的。我很确定他们只是像我在 5 人池中那样手动计算出来的。我认为有一个算法来自动化它会很有趣。
  • 我很想知道。如果他们通过让团队玩两次来解决问题,这可以在我的脚本中通过任意复制其中一个组合并将其推送到团队数组的末尾来完成。如果他们通过让一个团队坐在外面来做到这一点,这可以通过弹出团队数组中的最后一个组合来完成。
  • 匿名者使用 NP 完全算法的答案也有 6 名玩家池的重复。我开始认为至少一支球队必须一起比赛两次,这样所有球队才能至少一起比赛一次。如果在现实生活中是这种情况,那么两次一起比赛的球队将不会在第二场比赛中获得任何积分。
  • 是的,问题是 4 和 5 个玩家池分别导致 6 个和 10 个团队组合,因此您可以将它们平均分成两队比赛。但是 6 和 7 个玩家池会产生 15 和 21 个组合,因此您必须重复一个团队或离开一个团队以使数字相等。
【解决方案4】:

必须有更好的方法来做到这一点,但这是一个开始:

import itertools
import operator
from copy import deepcopy as clone

def getPossibleOpponents(numPlayers):
    matches = list(itertools.combinations(itertools.combinations(range(1,numPlayers+1), 2), 2))
    possibleMatches = [match for match in matches if len(set(itertools.chain.from_iterable(match)))==4]
    answer, playedTeams = {}, set()
    opponents = {}
    for team, teams in itertools.groupby(possibleMatches, key=operator.itemgetter(0)):
        playedTeams.add(team)
        opponents[team] = [t for t in next(teams) if t!=team]

    return opponents

def updateOpponents(opponents, playedTeams):
    for team in playedTeams:
        if team in opponents:
            opponents.pop(team)
    for k,v in opponents.items():
        opponents[k] = [team for team in v if team not in playedTeams]

def teamSeatings(opponents, answer=None):
    if answer is None:
        answer = {}
    if not len(opponents):
        if not(len(answer)):
            return None
        print(answer)
            sys.exit(0)

    for k,v in opponents.items():
        if not v:
            return None

        newOpponents = clone(opponents)
        for away in opponents[k]:
            if k in newOpponents:
                newOpponents.pop(k)
            answer[k] = away
            updateOpponents(newOpponents, {itertools.chain.from_iterable(i[0] for i in answer.items())})
            teamSeatings(newOpponents, answer)

if __name__ == "__main__":
    opps = getPossibleOpponents(5)
    teamSeatings(opps)

【讨论】:

  • 这个答案看起来不像是哪一方参加哪场比赛的列表。你确定这行得通吗?
  • @user2357112:我发布后不久就意识到我的帖子和答案之间还有一步。我现在正在努力这一步。所以我的帖子不是一个有效的答案......但是
【解决方案5】:

在组合学中,这称为 Whist Round Robin。也许对漫画感兴趣的数学专家更倾向于打惠斯特而不是沙滩排球?但那是另一回事了。

惠斯特循环赛

安排一场由两人组成的配对比赛的问题被称为 Whist Round Robin - 阅读更多并查找算法here

在玩家人数 4n 的情况下最容易实现。其他三个案例是使用幽灵玩家和幽灵团队构建的。应该面对幽灵队的玩家在这一轮中坐了下来。

基本的想法是一个玩家被锁定,比如说玩家一。然后其他玩家“轮换”,以便玩家 2 在第一轮与玩家 1 组队,并与玩家 2 和 3 会面。下一轮玩家 1 留下并与玩家 3 组队,他们面对玩家 2 和 4。看这个可视化我从上面的链接借来的。

我已经实现了那里描述的算法来安排 foosball 比赛,其特征与沙滩排球相似,而且效果很好。

在 python 中实现这个应该没有问题。如果你这样做 - 请回来提出一些具体问题。祝你好运! :)

【讨论】:

  • 我不认为这是完全相同的问题。问题是关于最小化比赛的数量,假设一次只有一场比赛,而惠斯特循环赛有一系列同时进行多场比赛的轮次。我不知道如何使用 WRR 的解决方案来最小化匹配次数。
【解决方案6】:

完全无向图是解决您问题的一个很好的模型:

  • 顶点代表玩家。

  • 边代表由两名玩家组成的团队。

对于每个匹配设置,您希望从不共享顶点的一组边中绘制两条边
您继续绘制边对,直到每条边至少绘制一次。

由于n个顶点的完整图中的边数为(n * (n - 1)) / 2,显然在这个数为奇数的情况下,一条边必须使用两次。

【讨论】:

    【解决方案7】:

    很抱歉继续在 Ruby 中发帖,但我想我刚刚破解了它,我必须分享。希望我所有的努力都能帮助您在 Python 中实现它:)。

    这个算法在没有我之前依赖的随机洗牌和递归函数的情况下工作。因此它适用于更大的池,在这种情况下我们不需要担心它们。

    num_players = gets.to_i
    players = (1..num_players).to_a
    teams = players.combination(2).to_a
    first_half = Float(teams.length / 2.0).ceil
    first_half_teams = teams[0..(first_half - 1)]
    second_half_teams = teams[first_half..-1]
    possible_lineups = []
    matches = []
    matched = []
    
    first_half_teams.each do |team|
      opponents = second_half_teams.select do |team_2|
        team - team_2 == team
      end
      possible_lineups << [team, opponents]
    end
    
    possible_lineups.each do |lineup|
      team_1 = lineup[0]
      team_2 = lineup[1].find do |team|
        !matched.include?(team)
      end
      if !team_2
        thief_team = possible_lineups.find do |test_team|
          test_team[1] - lineup[1] != test_team[1] &&
          test_team[1].find{ |opponent| !matched.include?(opponent) }
        end
        if thief_team
          new_opponent = thief_team[1].find{ |opponent| !matched.include?(opponent) }
          matched << new_opponent
          old_lineup = matches.find do |match|
            match[0] == thief_team[0]
          end
          team_2 = old_lineup[1]
          matches.find{ |match| match[0] == thief_team[0]}[1] = new_opponent
        else
          team_2 = second_half_teams.find do |team|
            lineup[0] - team == lineup[0]
          end
        end
      end
      matches << [team_1, team_2]
      matched << team_2
    end
    
    matches.each do |match|
      left_out = players.select{ |player| !match.flatten.include?(player) }
      print match, ", waiting: ", left_out, "\n"
    end
    
    print "greater: ", matches.flatten(1).find{ |team| matches.flatten(1).count(team) > teams.count(team) }, "\n"
    print "less: ", matches.flatten(1).find{ |team| matches.flatten(1).count(team) < teams.count(team) }, "\n"
    

    作为现实检查,我让脚本将最终的匹配数组与独特的玩家对组合的原始数组进行比较。如果玩家对组合的数量是偶数(例如池大小 = 4 或 5),则不应有任何对出现在最终匹配数组中的次数多于或少于它们在原始组合数组中出现的次数 (即每对应该在每个数组中恰好出现一次)。在组合数为奇数(n = 6 或 7)的情况下,匹配数组中的出现次数应该比组合数组中出现的次数多。永远不会有一对在匹配数组中出现的次数少于在组合数组中出现的次数。这是输出:

    4
    [[1, 2], [3, 4]], waiting: []
    [[1, 3], [2, 4]], waiting: []
    [[1, 4], [2, 3]], waiting: []
    greater: 
    less: 
    
    5
    [[1, 2], [3, 5]], waiting: [4]
    [[1, 3], [2, 4]], waiting: [5]
    [[1, 4], [2, 5]], waiting: [3]
    [[1, 5], [3, 4]], waiting: [2]
    [[2, 3], [4, 5]], waiting: [1]
    greater: 
    less: 
    
    6
    [[1, 2], [3, 4]], waiting: [5, 6]
    [[1, 3], [2, 6]], waiting: [4, 5]
    [[1, 4], [3, 5]], waiting: [2, 6]
    [[1, 5], [3, 6]], waiting: [2, 4]
    [[1, 6], [4, 5]], waiting: [2, 3]
    [[2, 3], [4, 6]], waiting: [1, 5]
    [[2, 4], [5, 6]], waiting: [1, 3]
    [[2, 5], [3, 4]], waiting: [1, 6]
    greater: [3, 4]
    less: 
    
    7
    [[1, 2], [3, 4]], waiting: [5, 6, 7]
    [[1, 3], [4, 5]], waiting: [2, 6, 7]
    [[1, 4], [3, 5]], waiting: [2, 6, 7]
    [[1, 5], [3, 6]], waiting: [2, 4, 7]
    [[1, 6], [3, 7]], waiting: [2, 4, 5]
    [[1, 7], [4, 6]], waiting: [2, 3, 5]
    [[2, 3], [4, 7]], waiting: [1, 5, 6]
    [[2, 4], [5, 6]], waiting: [1, 3, 7]
    [[2, 5], [6, 7]], waiting: [1, 3, 4]
    [[2, 6], [5, 7]], waiting: [1, 3, 4]
    [[2, 7], [3, 4]], waiting: [1, 5, 6]
    greater: [3, 4]
    less:
    

    FMc 备注:您的 cmets 帮助我完善了对这个问题的思考。 “脑死亡”算法让你接近,但并不完全是一个解决方案。当 n > 4 时,当您使用纯贪心算法时,似乎总是有一对玩家没有对手。我的算法通过返回并从已经匹配的团队中取出符合条件的对手来处理这个问题,当且仅当后者团队可以使用另一个尚未使用的对手时。这似乎是唯一需要的修复(除了调整奇数的组合),据我所知,它只需要完成一次。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-22
      • 2015-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多