Python 如何防止计算36k x 36k x 36k置换
我有一个很好的计划练习,我就是不能动脑(除了蛮力,它太大了,无法处理)。我们正在组织一次12人的高尔夫之旅。我们打了4天高尔夫球。每天有3次航班。(总共12个航班) 我们希望:Python 如何防止计算36k x 36k x 36k置换,python,math,fibonacci,Python,Math,Fibonacci,我有一个很好的计划练习,我就是不能动脑(除了蛮力,它太大了,无法处理)。我们正在组织一次12人的高尔夫之旅。我们打了4天高尔夫球。每天有3次航班。(总共12个航班) 我们希望: 最大限度地增加在飞行中相互比赛的独特玩家数量 但同时也希望尽量减少重复发生的次数(两名玩家相互玩了不止一次) 由于每次飞行有12名玩家和4名玩家,我每天大约可以在每次飞行中创建36k个玩家组合,因此计算变得非常密集。有没有更聪明的方法来解决这个问题?我的直觉告诉我斐波那契可以帮上忙,但不确定具体是如何帮上忙的 这是我
- 最大限度地增加在飞行中相互比赛的独特玩家数量
- 但同时也希望尽量减少重复发生的次数(两名玩家相互玩了不止一次)李>
import random
import itertools
import pandas as pd
def make_player_combi(day):
player_combis = []
for flight in day:
#print flight
for c in itertools.combinations(flight,2):
combi = list(sorted(c))
player_combis.append('-'.join(combi))
return player_combis
def make_score(a,b,c):
df = pd.DataFrame(a + b + c,columns=['player_combi'])['player_combi']
combi_counts = df.value_counts()
pairs_playing = len(combi_counts)
double_plays = combi_counts.value_counts().sort_index()
return pairs_playing, double_plays
players = ['A','B','C', 'D', 'E', 'F', 'G', 'H', 'I', 'J','K','L']
available_players = players[:]
n = 0
combinations_per_day = []
for players_in_flight_1 in itertools.combinations(players,4):
available_players_flight_1 = players[:]
available_players_flight_2 = players[:]
available_players_flight_3 = players[:]
for player in players_in_flight_1:
# players in flight1 can no longer be used in flight 2 or 3
available_players_flight_2.remove(player)
available_players_flight_3.remove(player)
for players_in_flight_2 in itertools.combinations(available_players_flight_2,4):
players_in_flight_3 = available_players_flight_3[:]
for player in players_in_flight_2:
players_in_flight_3.remove(player)
n = n + 1
print str(n), players_in_flight_1,players_in_flight_2,tuple(players_in_flight_3)
combinations_per_day.append([players_in_flight_1,players_in_flight_2,tuple(players_in_flight_3)])
n_max = 100 # limit to 100 entries max per day to save calculations
winning_list = []
max_score = 0
for day_1 in range(0,len(combinations_per_day[0:n_max])):
print day_1
for day_2 in range(0,len(combinations_per_day[0:n_max])):
for day_3 in range(0,len(combinations_per_day[0:n_max])):
a = make_player_combi(combinations_per_day[day_1])
b = make_player_combi(combinations_per_day[day_2])
x,y = make_score(a,b,c)
if x >= max_score:
max_score = x
my_result = {'pairs_playing' : x,
'double_plays' : y,
'max_day_1' : day_1,
'max_day_2' : day_2,
'max_day_3' : day_3
}
winning_list.append(my_result)
我选择了次优(但足够好)的解决方案,通过运行5百万个样本并获取最低的结果。。。感谢大家的深思熟虑我选择了次优(但足够好)的解决方案,运行了500万个样本,并取得了最低的结果。。。感谢大家一直以来的思考你可以通过消除对称性来强行实现这一点。让我们调用12个玩家
a、b、c、d、e、f、g、h、i、j、k、l
,编写一个包含4个玩家的航班:degj
,以及三个航班的一天日程安排:例如abcd efgh ijkl
第一天的航班是任意的:假设这三个航班是abcd efgh ijkl
在第二天和第三天,您有少于(12选择4)*(8选择4)的可能性,因为这将每个不同的时间表计算6次。例如,abcd efgh ijkl
、efgh abcd ijkl
和ijkl efgh abcd
都被视为单独的,但它们本质上是相同的。事实上,您有(12选择4)*(8选择4)/6=5775个不同的时间表
总的来说,这将为您提供5775*5775=33350625,这是一个可管理的3300万个可检查值
我们可以做得更好一点:我们不妨假设第2天和第3天的日程安排不同,不计算相同但第2天和第3天的日程安排互换的日程安排。这给了我们另一个几乎为2的因子
下面是实现所有这些功能的代码:
import itertools
import collections
# schedules generates all possible schedules for a given day, up
# to symmetry.
def schedules(players):
for c in itertools.combinations(players, 4):
for d in itertools.combinations(players, 4):
if set(c) & set(d):
continue
e = set(players) - set(c) - set(d)
sc = ''.join(sorted(c))
sd = ''.join(sorted(d))
se = ''.join(sorted(e))
if sc < sd < se:
yield sc, sd, se
# all_schedules generates all possible (different up to symmetry) schedules for
# the three days.
def all_schedules(players):
s = list(schedules(players))
d1 = s[0]
for d2, d3 in itertools.combinations(s, 2):
yield d1, d2, d3
# pcount returns a Counter that records how often each pair
# of players play each other.
def pcount(*days):
players = collections.Counter()
for d in days:
for flight in d:
for p1, p2 in itertools.combinations(flight, 2):
players[p1+p2] += 1
return players
def score(*days):
p = pcount(*days)
return len(p), sum(-1 for v in p.itervalues() if v > 1)
best = None
for days in all_schedules('abcdefghijkl'):
s = score(*days)
if s > best:
best = s
print days, s
这意味着在这三天里有48对独特的组合,并且有3对组合在一起玩了不止一次(ab
,fg
和kl
)
请注意,三对中的每一对每天玩一次以上的人。这是不幸的,可能意味着你需要调整你的想法如何得分的时间表。例如,排除同一对玩家玩两次以上的时间表,并取每个玩家看到的玩家数量的soft min,给出了以下解决方案:
abcd-efgh-ijkl abei-cfgj-dhkl acfk-begl-dhij
这有45对独特的配对,9对相互玩了不止一次。但每个玩家都会遇到至少7个不同的玩家,在实践中可能比上面的“最佳”解决方案更可取。你可以通过消除对称性来强行实现这一点。让我们调用12个玩家
a、b、c、d、e、f、g、h、i、j、k、l
,编写一个包含4个玩家的航班:degj
,以及三个航班的一天日程安排:例如abcd efgh ijkl
第一天的航班是任意的:假设这三个航班是abcd efgh ijkl
在第二天和第三天,您有少于(12选择4)*(8选择4)的可能性,因为这将每个不同的时间表计算6次。例如,abcd efgh ijkl
、efgh abcd ijkl
和ijkl efgh abcd
都被视为单独的,但它们本质上是相同的。事实上,您有(12选择4)*(8选择4)/6=5775个不同的时间表
总的来说,这将为您提供5775*5775=33350625,这是一个可管理的3300万个可检查值
我们可以做得更好一点:我们不妨假设第2天和第3天的日程安排不同,不计算相同但第2天和第3天的日程安排互换的日程安排。这给了我们另一个几乎为2的因子
下面是实现所有这些功能的代码:
import itertools
import collections
# schedules generates all possible schedules for a given day, up
# to symmetry.
def schedules(players):
for c in itertools.combinations(players, 4):
for d in itertools.combinations(players, 4):
if set(c) & set(d):
continue
e = set(players) - set(c) - set(d)
sc = ''.join(sorted(c))
sd = ''.join(sorted(d))
se = ''.join(sorted(e))
if sc < sd < se:
yield sc, sd, se
# all_schedules generates all possible (different up to symmetry) schedules for
# the three days.
def all_schedules(players):
s = list(schedules(players))
d1 = s[0]
for d2, d3 in itertools.combinations(s, 2):
yield d1, d2, d3
# pcount returns a Counter that records how often each pair
# of players play each other.
def pcount(*days):
players = collections.Counter()
for d in days:
for flight in d:
for p1, p2 in itertools.combinations(flight, 2):
players[p1+p2] += 1
return players
def score(*days):
p = pcount(*days)
return len(p), sum(-1 for v in p.itervalues() if v > 1)
best = None
for days in all_schedules('abcdefghijkl'):
s = score(*days)
if s > best:
best = s
print days, s
这意味着在这三天里有48对独特的组合,并且有3对组合在一起玩了不止一次(ab
,fg
和kl
)
请注意,三对中的每一对每天玩一次以上的人。这是不幸的,可能意味着你需要调整你的想法如何得分的时间表。例如,排除同一对玩家玩两次以上的时间表,并取每个玩家看到的玩家数量的soft min,给出了以下解决方案:
abcd-efgh-ijkl abei-cfgj-dhkl acfk-begl-dhij
这有45对独特的配对,9对相互玩了不止一次。但是每个玩家至少会遇到7个不同的玩家,在实践中可能比上面的“最优”解决方案更可取。数学评论:对于单次飞行,一个人有
多项式[12;4,4,4]=34650
的可能性。对于12次飞行,你可以重复选择12次。这使得建立12个航班成为可能。对暴力来说太过分了;-)我的第一个猜测是,这可以被表述为一个整数规划问题。整数规划是一种约束优化,其中的解必须在整数中找到。有各种各样的软件包来解决这些问题。我使用了自由软件GLPK解决相关问题,它对我来说效果很好。您需要用特定于领域的语言表达您的问题,然后由GPLK处理。通常,表达问题比找到解决方案要简单得多,所以这是一个巨大的胜利。你能解释一下“最大限度地增加在飞行中相互比赛的独特玩家的数量”是什么意思吗?我不明白。另外,我是否正确理解您为每次飞行选择了一个4人的新团队?还是你每天只选择新的团队?谢谢你的澄清,罗伯特。。。我