体育赛程中实现队伍多场比赛尽量相邻的排序算法求解
解决思路
这个场景不需要用复杂的约束规划工具,用图论建模即可高效解决:
- 把每支队伍当作无向图的节点,每场对阵当作连接两个节点的无向边。你当前场景下每队恰好打2场,所有节点的度数都是2,整个图天然由若干个互不相交的环构成。
- 对每个环进行遍历,遍历过程中经过的边就是排序后的对阵,相邻边必然共享一个节点,也就是对应共享队伍的两场比赛完全背靠背相邻,完美匹配需求。
- 如果后续扩展为部分队伍参与超过2场的场景,也可以用贪心策略补全:每次优先选择和最后一场已排比赛共享队伍的未排对阵接在后面,最大化相邻概率。
可运行代码实现
def schedule_sort(matches): # 构建邻接表:key为队伍,value存储(对手队伍,对阵元组) adj = dict() # 存储未安排的比赛,避免重复调度 unused_matches = set() for team_a, team_b in matches: if team_a not in adj: adj[team_a] = list() if team_b not in adj: adj[team_b] = list() adj[team_a].append((team_b, (team_a, team_b))) adj[team_b].append((team_a, (team_a, team_b))) unused_matches.add((team_a, team_b)) sorted_matches = [] while unused_matches: # 取任意未安排的比赛作为当前环的起点 start_match = next(iter(unused_matches)) current_team = start_match[0] prev_team = None # 遍历整个环 while True: # 找当前队伍未安排的对阵 for neighbor, match in adj[current_team]: if match in unused_matches: sorted_matches.append(match) unused_matches.remove(match) prev_team = current_team current_team = neighbor break # 回到环起点,结束当前环的遍历 if current_team == start_match[0]: break return sorted_matches
效果测试
输入你提供的初始对阵:
original_matches = [('t05', 't09'), ('t07', 't03'), ('t01', 't09'), ('t03', 't01'), ('t07', 't05'), ('t02', 't06'), ('t04', 't06'), ('t10', 't08'), ('t10', 't04'), ('t08', 't02')] print(schedule_sort(original_matches))
输出示例(环的起点不同输出顺序会有差异,但所有队伍的两场比赛基本都相邻,仅每个环会有1支队伍的两场分别在环序列的首尾,属于环拆线性的天然特性,可通过调整环的拆分点、多环拼接时优先匹配相邻环的首尾共享队伍进一步优化):
[('t05', 't09'), ('t01', 't09'), ('t03', 't01'), ('t07', 't03'), ('t07', 't05'), ('t02', 't06'), ('t04', 't06'), ('t10', 't04'), ('t10', 't08'), ('t08', 't02')]
内容的提问来源于stack exchange,提问作者dabadaba
相关产品推荐
相关产品推荐

