Я разрабатываю алгоритм, который создает оптимальные команды на основе доступности каждого (максимизирует общую доступность). С этой целью я создал функцию, которая берет словарь доступности, отображающий человека в массив их доступности в течение недели каждые 15 минут (например, [True, True, False,…,False]) и желаемый размер команды и результаты финальных команд. Вот мой рабочий код:
import numpy as np
from itertools import combinations, chain
import operator
from functools import reduce
from tqdm import tqdm
import operator
def ncr(n, r):
"""N Choose R combination"""
r = min(r, n-r)
numer = reduce(operator.mul, range(n, n-r, -1), 1)
denom = reduce(operator.mul, range(1, r+1), 1)
return numer // denom # or / in Python 2
NUM_PEOPLE = 100
TEAM_SIZE = 5
time_slots = 24*4*7
# random availabilities
availabilities = np.random.randint(2, size=(NUM_PEOPLE, time_slots), dtype="bool")
availabilities_dict = {}
for i, availability in enumerate(availabilities):
availabilities_dict[i] = availability
def make_teams(availabilities_dict, team_size):
"""
availabilities_dict form: {player: [0,0,0,...,1], player2: [0,0,0,0,1...,0]}
"""
sums = []
comb = combinations(availabilities_dict, TEAM_SIZE)
for i in tqdm(list(comb)):
sum_of_array = np.logical_and.reduce((np.array(availabilities[i,:]))).sum()
sums.append((i, sum_of_array))
sums.sort(key=operator.itemgetter(1))
sums.reverse()
assigned = []
teams = []
i = 0
while (len(assigned) < NUM_PEOPLE):
considering = list(sums[i][0])
none_assigned = True
for person in considering:
if person in assigned:
none_assigned = False
if none_assigned:
teams.append((considering, sums[i][1]))
for person in considering:
assigned.append(person)
i += 1
return teams
teams = make_teams(availabilities_dict, TEAM_SIZE)
Пример вывода состоит из списка кортежей (команда, общее количество пересекающихся блоков):
[([15, 18, 42, 70, 94], 36),
([14, 30, 63, 80, 97], 36),
([1, 12, 40, 64, 88], 36),
([22, 48, 62, 72, 87], 34),
([25, 29, 35, 53, 85], 32),
([26, 31, 49, 60, 78], 31),
([13, 44, 79, 93, 96], 29),
([32, 59, 67, 71, 82], 28),
([24, 39, 41, 50, 91], 28),
([9, 28, 55, 92, 95], 28),
([5, 8, 11, 19, 86], 28),
([4, 33, 56, 76, 83], 27),
([2, 10, 16, 17, 69], 27),
([21, 43, 73, 75, 81], 24),
([7, 20, 57, 89, 99], 24),
([23, 36, 37, 58, 66], 22),
([52, 61, 65, 68, 84], 20),
([3, 27, 34, 47, 74], 18),
([6, 38, 51, 54, 77], 16),
([0, 45, 46, 90, 98], 9)]
Но это заняло более 10 минут, чтобы работать на моем современном компьютере! Есть ли способ найти оптимальный командный матч, не перебирая все возможные комбинации? Как мне сделать это быстрее? Спасибо!