保持双头背靠背的排序算法
Sorting algorithm to keep doubleheaders back-to-back
在运动日程安排的背景下,我有一个游戏列表,其中球队可能会玩超过 1 场比赛。如果是这样的话,他们的比赛应该是背靠背的。由于配对的性质,这可能不可行,至少它们应该尽可能靠近。
这是初始配对的示例,其中每个团队都玩 2x:
[('t05', 't09'), ('t07', 't03'), ('t01', 't09'), ('t03', 't01'), ('t07', 't05'), ('t02', 't06'), ('t04', 't06'), ('t10', 't08'), ('t10', 't04'), ('t08', 't02')]
请注意,这不是每支球队在主客场比赛中每隔两场比赛的双循环赛制。这只是一个团队进行两场比赛的配置。
我正在尝试实施一种算法来对这些比赛进行排序,以使每支球队的比赛尽可能接近。这是第一个简单的方法:
matches = list(matches)
c = collections.Counter([t for m in matches for t in m.teams])
for t, n in c.iteritems():
if n > 1:
# matches containing the team t
indices = [i for i, m in enumerate(matches) if t in m.teams]
for i in indices:
# bring these matches to the front
matches.insert(0, matches.pop(i))
return matches
这是结果:
[('t10', 't04'), ('t10', 't08'), ('t01', 't09'), ('t05', 't09'), ('t08', 't02'), ('t07', 't03'), ('t07', 't05'), ('t02', 't06'), ('t04', 't06'), ('t03', 't01')]
显然这不是很好,因为它是一方面的,通过将他们的游戏放在列表的前面,它使列表末尾的团队受益更多。对于单边,我的意思是它在每场比赛中只看一支球队,并为那支球队进行排序,而忽略第二支球队,这将打破另一支球队的背靠背平衡。
这将是使用约束规划进行最大化的完美案例,例如使用 python-constraint or pyomo。但是我真的很不擅长建模约束满足问题 (CSP),所以我不知道从哪里开始处理这个案例。
有什么想法吗?
递归函数可以尝试以动态编程方式进行各种排序,这种方式优先考虑连接的游戏而不是序列中的中断。
这个没有特别优化,但对于小的游戏列表应该足够快:
def gameOrder(games,prevGame=None):
if len(games)==1: return games # base condition (only one game)
best,breaks = games,len(games)-1 # track best order and number of breaks
for strict in (1,0): # prioritize connections over breaks
for i,game in enumerate(games): # each game as 1st in sequence
if breaks <= strict: return best # minimum breaks reached
if strict and prevGame and prevGame.isdisjoint(game):
continue # does not connect to previous (strict)
seq = [game]+gameOrder(games[:i]+games[i+1:],set(game)) # sort rest
brk = sum(set(g1).isdisjoint(g2) for g1,g2 in zip(seq,seq[1:]))
if brk < breaks:
breaks,best = brk,seq # track best so far
return best # return best found
输出:
games = [('t05', 't09'), ('t07', 't03'), ('t01', 't09'), ('t03', 't01'),
('t07', 't05'), ('t02', 't06'), ('t04', 't06'), ('t10', 't08'),
('t10', 't04'), ('t08', 't02')]
print(gameOrder(games)) # only one break between (t07,t05) and (t02,t06)
[('t05', 't09'), ('t01', 't09'), ('t03', 't01'), ('t07', 't03'),
('t07', 't05'), ('t02', 't06'), ('t04', 't06'), ('t10', 't04'),
('t10', 't08'), ('t08', 't02')]
请注意,这可以确保尽可能多的球队连续比赛。如果您的目标是尽量减少任何球队比赛之间的最坏情况 'distance',或尽量减少每支球队的平均比赛距离,这可能不是最佳解决方案。
在运动日程安排的背景下,我有一个游戏列表,其中球队可能会玩超过 1 场比赛。如果是这样的话,他们的比赛应该是背靠背的。由于配对的性质,这可能不可行,至少它们应该尽可能靠近。
这是初始配对的示例,其中每个团队都玩 2x:
[('t05', 't09'), ('t07', 't03'), ('t01', 't09'), ('t03', 't01'), ('t07', 't05'), ('t02', 't06'), ('t04', 't06'), ('t10', 't08'), ('t10', 't04'), ('t08', 't02')]
请注意,这不是每支球队在主客场比赛中每隔两场比赛的双循环赛制。这只是一个团队进行两场比赛的配置。
我正在尝试实施一种算法来对这些比赛进行排序,以使每支球队的比赛尽可能接近。这是第一个简单的方法:
matches = list(matches)
c = collections.Counter([t for m in matches for t in m.teams])
for t, n in c.iteritems():
if n > 1:
# matches containing the team t
indices = [i for i, m in enumerate(matches) if t in m.teams]
for i in indices:
# bring these matches to the front
matches.insert(0, matches.pop(i))
return matches
这是结果:
[('t10', 't04'), ('t10', 't08'), ('t01', 't09'), ('t05', 't09'), ('t08', 't02'), ('t07', 't03'), ('t07', 't05'), ('t02', 't06'), ('t04', 't06'), ('t03', 't01')]
显然这不是很好,因为它是一方面的,通过将他们的游戏放在列表的前面,它使列表末尾的团队受益更多。对于单边,我的意思是它在每场比赛中只看一支球队,并为那支球队进行排序,而忽略第二支球队,这将打破另一支球队的背靠背平衡。
这将是使用约束规划进行最大化的完美案例,例如使用 python-constraint or pyomo。但是我真的很不擅长建模约束满足问题 (CSP),所以我不知道从哪里开始处理这个案例。
有什么想法吗?
递归函数可以尝试以动态编程方式进行各种排序,这种方式优先考虑连接的游戏而不是序列中的中断。
这个没有特别优化,但对于小的游戏列表应该足够快:
def gameOrder(games,prevGame=None):
if len(games)==1: return games # base condition (only one game)
best,breaks = games,len(games)-1 # track best order and number of breaks
for strict in (1,0): # prioritize connections over breaks
for i,game in enumerate(games): # each game as 1st in sequence
if breaks <= strict: return best # minimum breaks reached
if strict and prevGame and prevGame.isdisjoint(game):
continue # does not connect to previous (strict)
seq = [game]+gameOrder(games[:i]+games[i+1:],set(game)) # sort rest
brk = sum(set(g1).isdisjoint(g2) for g1,g2 in zip(seq,seq[1:]))
if brk < breaks:
breaks,best = brk,seq # track best so far
return best # return best found
输出:
games = [('t05', 't09'), ('t07', 't03'), ('t01', 't09'), ('t03', 't01'),
('t07', 't05'), ('t02', 't06'), ('t04', 't06'), ('t10', 't08'),
('t10', 't04'), ('t08', 't02')]
print(gameOrder(games)) # only one break between (t07,t05) and (t02,t06)
[('t05', 't09'), ('t01', 't09'), ('t03', 't01'), ('t07', 't03'),
('t07', 't05'), ('t02', 't06'), ('t04', 't06'), ('t10', 't04'),
('t10', 't08'), ('t08', 't02')]
请注意,这可以确保尽可能多的球队连续比赛。如果您的目标是尽量减少任何球队比赛之间的最坏情况 'distance',或尽量减少每支球队的平均比赛距离,这可能不是最佳解决方案。