问题描述
我正在想办法匹配 3 个团队中的 n 个玩家(n 很可能不会超过 30,并且是 3 的倍数)。匹配将基于他们的等级(数字越小,玩家越熟练)
我认为合理的目标是匹配球队中的球员,使得球队平均排名(每队排名总和除以3)之间的最大差异尽可能小(即之间的差异)平均排名最高的队伍和平均排名最低的队伍应该尽可能小)。
我想过尝试所有可能的排列,但这是不可能的,因为复杂度为 n! (并且输入很容易超过 20 个或更多)
我能想到的唯一可行(但非常幼稚)的解决方案是这样的: 假设我们有 12 名需要在团队中匹配的球员。我们将根据排名对它们进行排序,然后将排序后的列表分成 3 部分,每部分包含 4 名玩家(第 1 名 4 名玩家最熟练,第 2 名 4 名玩家熟练,第 3 名 4 名玩家最不熟练),然后我将继续取第一部分的第一个玩家和最后一部分的最后一个玩家,第一部分的第二个玩家和最后一部分的 (last-1) 等等......
然后我将根据他们的平均排名对这些 2 进行排序,然后将中间部分(第二部分)的第 1 名球员与平均排名最高的球队,第 2 部分的第 2 名球员与球队平均排名第二高等......
这当然不是最佳解决方案。所以我想知道是否有可行的方法来解决这个问题,从而产生更优化的解决方案?
谢谢
解决方法
适用于您的界限的简单方法
首先,我们可以考虑一个明显最优的团队分布:每个团队的排名总和完全相同。不幸的是,这并不总是可行的,因为有时团队的平均实力不是整数。
我们能得到的最接近这个理想的是只允许具有平均值的团队向上或向下取整。例如,如果有 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)
不过,我再次不建议实际使用此代码。