允许重复选行的线性优化问题:球员出场次数约束添加咨询
阵容选取线性优化问题实现指导
现有思路校验
你当前的建模方向是合理的,核心逻辑是将每行阵容的选取次数设为整数决策变量,在此基础上叠加约束、设置目标函数即可完成求解。需要注意原代码中直接用列表作为LpVariable.dicts的key可能触发不可哈希错误,建议先将阵容按索引编号,用索引作为变量的唯一标识。
完整实现步骤
- 预处理球员-阵容关联映射
import pandas as pd from pulp import LpProblem, LpMaximize, LpVariable, lpSum, PULP_CBC_CMD # 你已有的初始化代码 prob = LpProblem('LineUp Optimization', LpMaximize) lineups = df.values.tolist() cap = dict(zip(players, player_df['Cap'])) # 新增:建立球员到包含该球员的阵容索引的映射 player_to_lineups = {p: [] for p in players} for lineup_idx, lineup_players in enumerate(lineups): for p in lineup_players: if p in player_to_lineups: player_to_lineups[p].append(lineup_idx) # 修正变量定义,用索引作为key避免哈希问题 lineup_var = LpVariable.dicts('Lineups', range(len(lineups)), lowBound=0, cat='Integer')
- 添加球员出场次数约束
对每个球员,所有包含该球员的阵容被选次数之和不能超过其最大允许次数:
for player, max_count in cap.items(): prob += ( lpSum([lineup_var[idx] for idx in player_to_lineups[player]]) <= max_count, f"MaxOccur_{player}" )
- 设置目标函数
如果你的需求是尽可能多选符合约束的阵容,直接最大化总选取次数即可:
prob += lpSum([lineup_var[idx] for idx in range(len(lineups))]), "TotalSelectedLineups"
如果有阵容评分体系,也可以替换为各阵容的评分乘以选取次数的加权和,实现优先选高分阵容的效果。
- 非精确解求解配置
因为你不需要完全精确的最优解,可以设置MIP相对间隙参数,在解的精度和求解速度之间做平衡,例如设置间隙为5%,即找到的解和理论最优解的差距不超过5%时就停止求解:
# 启用CBC求解器,设置相对间隙为0.05,开启日志输出 prob.solve(PULP_CBC_CMD(msg=True, gapRel=0.05))
结果输出
求解完成后提取结果,按原始输入格式输出即可:
output_rows = [] for idx in range(len(lineups)): select_times = int(round(lineup_var[idx].varValue)) # 按选取次数重复添加对应行 output_rows += [lineups[idx]] * select_times # 转DataFrame后输出和原始格式完全一致的结果 output_df = pd.DataFrame(output_rows, columns=df.columns) print(output_df.to_string(index=True))
提示:如果有额外约束(比如总阵容数固定、特定球员组合不能同时出现等),可以在约束添加阶段自行补充对应规则即可。
内容的提问来源于stack exchange,提问作者Scott Woodhall
相关产品推荐
相关产品推荐

