基于玩家rating与阈值矩阵的最优组队算法求解咨询
问题建模
首先先把你描述的规则抽象成可复用的计算逻辑,不管规则矩阵的具体数值是什么,先定义两个基础函数:
get_unit_score(k, total_rating):输入单队人数k、队伍总rating值,返回当前队伍下每名玩家可贡献的score,达不到对应阈值则返回0calc_team_score(players):输入一个玩家列表,返回该队伍的总score,计算逻辑为len(players) * get_unit_score(len(players), sum(p.rating for p in players))
问题可归纳为典型的带约束的组合优化问题:
- 每个玩家最多加入1个队伍,也可以不加入任何队伍
- 单队人数必须是规则矩阵支持的合法取值
- 优化目标为所有已组建队伍的总score之和最大
小数据量(玩家数≤50)精确求解方案
如果你的玩家总数不多,直接用精确求解就能拿到全局最优解,不需要做近似。
方案1:状态压缩动态规划(适用玩家数≤20)
- 状态定义:
dp[mask]表示选中二进制标识mask对应的玩家时,能拿到的最大总score(mask第i位为1表示第i个玩家已被使用) - 初始值:
dp[0] = 0,其余状态初始为0 - 状态转移:遍历所有状态
mask,再遍历所有未被使用的玩家的合法子集(人数符合规则要求),计算该子集的队伍score,更新新状态的最大值:new_mask = mask | subset_mask dp[new_mask] = max(dp[new_mask], dp[mask] + calc_team_score(subset_players)) - 最终结果:取
dp数组中的最大值(不需要用完所有玩家)
方案2:整数规划(适用玩家数≤50)
用现成的运筹学求解器(比如Google OR-Tools)可以快速求解:
- 生成所有合法候选队伍:遍历所有人数符合规则的玩家子集,过滤掉
calc_team_score为0的无收益队伍 - 定义决策变量:
x[t]为0或1,1表示选中第t个候选队伍,0表示不选 - 约束条件:每个玩家最多属于1个队伍,即所有包含玩家i的候选队伍的
x[t]之和 ≤ 1 - 目标函数:最大化
sum(x[t] * team_score[t])
大数据量(玩家数>50)近似求解方案
玩家数超过50之后精确求解的时间成本会指数级上升,用启发式算法可以拿到接近最优的结果,工程上足够用。
基础贪心策略
- 先把所有玩家按rating从高到低排序
- 预计算不同队伍人数的单位rating收益(每1点总rating可兑换的score),优先组建收益最高的人数规模的队伍
- 从rating最高的玩家开始尝试凑对应规模的队伍,凑成后计算总收益,如果比拆分成更小队伍的收益高就保留,否则拆分
- 遍历完成后做局部调优:随机尝试拆队重组、跨队换玩家的操作,只要总score提升就保留,直到没有优化空间为止
进阶智能算法
如果对精度要求更高,可以用模拟退火或者遗传算法:
- 遗传算法:用每个玩家的分组编号作为编码(0表示不组队,相同编号表示同队),交叉变异时保证单队人数合法,迭代若干代后即可得到接近最优的解
- 模拟退火:每次随机做一次调整(拆队、组新队、跨队换玩家),收益提升就直接接受,收益下降则按概率接受,避免陷入局部最优,迭代足够多次后效果接近全局最优
注意事项
- 所有计算出的总score≤0的队伍直接放弃,宁可让玩家闲置也不要组负收益/零收益队伍
- 高rating玩家优先组队,通常高总rating的队伍单位rating收益更高,可以大幅提升整体总score
内容的提问来源于stack exchange,提问作者Astudent
相关产品推荐
相关产品推荐

