【问题标题】:Matching players in teams based on their rank根据排名匹配球队中的球员
【发布时间】:2021-01-26 12:40:31
【问题描述】:

我正在想办法让 n 名球员分成 3 人一组(n 很可能不会超过 30 并且是 3 的倍数)。匹配将根据他们的排名(数字越低,玩家越熟练)

我认为合理的目标是匹配团队中的玩家,使得团队平均排名之间的最大差异(每个团队的排名总和除以 3)尽可能小(即平均排名最高的队伍和平均排名最低的队伍应该尽量少)。

我曾想过尝试所有可能的排列,但那是不可能的,因为复杂度是 n! (而且输入很容易超过 20 或更多)

我能想到的唯一可行(但非常天真)的解决方案是这样的: 假设我们有 12 名球员需要组队匹配。我们将根据排名对其进行排序,然后将排序后的列表分为 3 部分,每部分包含 4 位玩家(第 4 位玩家技能最高,第 4 位玩家技能一般,第 4 位玩家技能最低),然后我将继续将第一部分的第一个玩家与最后一个部分的最后一个玩家、第一部分的第二个玩家与最后一部分的 (last-1) 等......

然后我会根据他们的平均排名对他们进行排序,然后将中间部分(第二部分)的第一个玩家放在平均排名最高的团队中,将第二部分的第二个玩家放在团队中平均排名第二等.....

这当然不是最佳解决方案。所以我想知道是否有可行的方法来解决这个问题,从而产生更优化的解决方案?

谢谢

【问题讨论】:

  • 您建议的方法有什么问题?
  • 这不是非常理想的(我认为),非常临时和非常贪婪。我在问是否有更好的方法可以产生更优化的解决方案。

标签: algorithm data-structures matching


【解决方案1】:

一种适用于您的界限的简单方法

首先,我们可以考虑一个明显最优的团队分布:每个团队的排名总和完全相同。不幸的是,这并不总是可行的,因为有时团队的平均力量不是整数。

我们能得到的最接近这个理想的方法是只允许平均实力的球队向上或向下取整。例如,有 4 支球队和 12 名球员,一支球队的平均排名总和为 19.5,这意味着理想情况下,我们将有两支力量为 19 的球队和两支力量为 20 的球队。

考虑到所有团队的理想实力,我编写了一个快速脚本来组建这些团队。具体来说,它会随机选择两名球员组成一支球队,然后我们可以计算出第三名球员应该是谁。如果所需的第三个玩家还没有团队,这三个人组成一个团队,否则我们只需再试一次。如果多次尝试仍无法组队,我们将重新开始。

因为这种方法可以随机到达任意排列,卡住时会重新启动,如果存在则保证找到最优解。

有两个缺点:它可能非常低效,而且我还没有证明存在最佳解决方案。然而,对于少于 100 名玩家,脚本会在合理的时间内找到最优解,从而也证明最优解存在。

结果

脚本生成的结果是 in this pastebin,开箱即用,最多可用于 42 支球队(126 名球员)。

Python 脚本本身写得很糟糕,优化很差,而且通常很糟糕,以至于我很犹豫将其上传到这里。我希望任何人都能够根据上述总体思路制作出更好的版本。但是,SO要求pastebin链接要附上代码,所以这里是:

from __future__ import division, print_function
import random
import sys

def solve(teams, players):
    playerset = set(players)
    result = None
    while True:
        result = []
        taken = set()
        for team in teams:
            for _ in range(len(teams) * 10):
                first = random.choice(players)
                while first in taken:
                    first = random.choice(players)
                second = random.choice(players)
                while second == first or second in taken or not team - first - second in playerset or team - first - second in [first, second]:
                    second = random.choice(players)
                third = team - first - second
                if third not in taken:
                    result.append(sorted([first, second, third]))
                    taken.add(first)
                    taken.add(second)
                    taken.add(third)
                    break
            else:
                break
        else:
            print_solution(result)
            return
            
def print_solution(result):
    for i, team in enumerate(result):
        print("{}: {}, {}, {}".format(i+1, *team))
    print()
    sys.stdout.flush()

def get_team_strengths(N_teams, players):
    s = sum(players)
    mean = s/N
    target = mean*3
    teams = [int(target)]*N_teams
    teams.sort()
    while sum(teams) != s:
        if sum(teams) > s:
            teams[-1] -= 1
        else:
            teams[0] += 1
        teams.sort()
    return teams

for N_teams in range(1, 43):
    N = N_teams * 3
    players = list(range(1, N+1))
    teams = get_team_strengths(N_teams, players)
    print("{} teams:".format(N_teams))
    solve(teams, players)

不过,我不建议实际使用此代码。

【讨论】:

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