Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何防止计算36k x 36k x 36k置换_Python_Math_Fibonacci - Fatal编程技术网

Python 如何防止计算36k x 36k x 36k置换

Python 如何防止计算36k x 36k x 36k置换,python,math,fibonacci,Python,Math,Fibonacci,我有一个很好的计划练习,我就是不能动脑(除了蛮力,它太大了,无法处理)。我们正在组织一次12人的高尔夫之旅。我们打了4天高尔夫球。每天有3次航班。(总共12个航班) 我们希望: 最大限度地增加在飞行中相互比赛的独特玩家数量 但同时也希望尽量减少重复发生的次数(两名玩家相互玩了不止一次) 由于每次飞行有12名玩家和4名玩家,我每天大约可以在每次飞行中创建36k个玩家组合,因此计算变得非常密集。有没有更聪明的方法来解决这个问题?我的直觉告诉我斐波那契可以帮上忙,但不确定具体是如何帮上忙的 这是我

我有一个很好的计划练习,我就是不能动脑(除了蛮力,它太大了,无法处理)。我们正在组织一次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人的新团队?还是你每天只选择新的团队?谢谢你的澄清,罗伯特。。。我