Найдите оптимальные команды при наличии календаря

Я разрабатываю алгоритм, который создает оптимальные команды на основе доступности каждого (максимизирует общую доступность). С этой целью я создал функцию, которая берет словарь доступности, отображающий человека в массив их доступности в течение недели каждые 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 минут, чтобы работать на моем современном компьютере! Есть ли способ найти оптимальный командный матч, не перебирая все возможные комбинации? Как мне сделать это быстрее? Спасибо!

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *