ORTools/Python:求解最优球队时如何追踪同俱乐部/国家球员选中数量?
解决方案
核心思路
要解决这个问题,关键是把「同俱乐部/国家/联赛且处于最佳位置的选中球员数量」转化为OR-Tools能识别的变量和约束,再将数量映射到0-3的参数值,最终代入目标函数。
步骤1:定义分组计数变量
针对俱乐部、国家、联赛三个维度,分别创建整数变量来记录对应分组中「处于最佳位置且被选中」的球员数量:
# 假设roster是所有球员卡列表,每个card有club、country、league、best_position属性 club_counts = {} country_counts = {} league_counts = {} # 初始化俱乐部计数变量 for card in roster: club = card.club if club not in club_counts: # 最多11人,所以范围0-11 club_counts[club] = model.NewIntVar(0, 11, f"club_count_{club}") # 国家和联赛的计数变量同理 for card in roster: country = card.country if country not in country_counts: country_counts[country] = model.NewIntVar(0, 11, f"country_count_{country}") for card in roster: league = card.league if league not in league_counts: league_counts[league] = model.NewIntVar(0, 11, f"league_count_{league}")
步骤2:建立计数变量与选中状态的约束
让计数变量等于对应分组中「处于最佳位置且被选中」的球员数量之和(card_vars是布尔变量,求和即计数):
# 俱乐部计数约束 for club in club_counts: model.Add(club_counts[club] == sum( card_vars[(card, card.best_position)] for card in roster if card.club == club )) # 国家计数约束 for country in country_counts: model.Add(country_counts[country] == sum( card_vars[(card, card.best_position)] for card in roster if card.country == country )) # 联赛计数约束 for league in league_counts: model.Add(league_counts[league] == sum( card_vars[(card, card.best_position)] for card in roster if card.league == league ))
步骤3:将计数映射为0-3的参数值
创建bonus变量,通过约束将计数范围映射到0-3的参数(按游戏规则:0人→0,1人→1,2人→2,≥3人→3):
# 俱乐部bonus变量 club_bonus = {} for club in club_counts: club_bonus[club] = model.NewIntVar(0, 3, f"club_bonus_{club}") # 添加映射约束 model.Add(club_bonus[club] == 0).OnlyEnforceIf(club_counts[club] == 0) model.Add(club_bonus[club] == 1).OnlyEnforceIf(club_counts[club] == 1) model.Add(club_bonus[club] == 2).OnlyEnforceIf(club_counts[club] == 2) model.Add(club_bonus[club] == 3).OnlyEnforceIf(club_counts[club] >= 3) # 国家和联赛的bonus变量同理 country_bonus = {} for country in country_counts: country_bonus[country] = model.NewIntVar(0, 3, f"country_bonus_{country}") model.Add(country_bonus[country] == 0).OnlyEnforceIf(country_counts[country] == 0) model.Add(country_bonus[country] == 1).OnlyEnforceIf(country_counts[country] == 1) model.Add(country_bonus[country] == 2).OnlyEnforceIf(country_counts[country] == 2) model.Add(country_bonus[country] == 3).OnlyEnforceIf(country_counts[country] >= 3) league_bonus = {} for league in league_counts: league_bonus[league] = model.NewIntVar(0, 3, f"league_bonus_{league}") model.Add(league_bonus[league] == 0).OnlyEnforceIf(league_counts[league] == 0) model.Add(league_bonus[league] == 1).OnlyEnforceIf(league_counts[league] == 1) model.Add(league_bonus[league] == 2).OnlyEnforceIf(league_counts[league] == 2) model.Add(league_bonus[league] == 3).OnlyEnforceIf(league_counts[league] >= 3)
步骤4:调整目标函数
将calculate_rating的第三个参数替换为对应的bonus值(这里假设游戏取俱乐部加成,若需要叠加多个维度,可在calculate_rating中处理):
model.Maximize(sum([ card.calculate_rating(position, coefficients, club_bonus[card.club]) * card_vars[(card, position)] for card in roster for position in max_player_positions ]))
额外约束补充
确保球员不会被重复选中,且总人数为11:
# 每个球员最多被选中一次 for card in roster: model.Add(sum(card_vars[(card, pos)] for pos in max_player_positions) <= 1) # 总选中人数为11 model.Add(sum(card_vars.values()) == 11)
内容的提问来源于stack exchange,提问作者Bastien_F
相关产品推荐
相关产品推荐

