Проблема с назначением с 2 работниками на работу

#algorithm #linear-programming #hungarian-algorithm #assignment-problem

Вопрос:

Настройка проблемы

В настоящее время мы работаем над решением проблемы отправки для стартапа в области пищевых технологий (электронного магазина). У нас есть рабочие места (заказы должны быть доставлены) и работники (курьеры/упаковщики/универсалы) Проблема заключается в том, чтобы эффективно распределять заказы между работниками. На первом этапе мы решили оптимизировать CTE (время между размещением заказа и доставкой заказа). Нажмите, чтобы съесть.

Сама проблема

Проблема заключается в том, что иногда эффективно иметь 2 работника на одно задание, а не одного исполнителя, потому что упаковщик может знать «карту» магазина, а у курьера может быть велосипед, что позволяет выполнять работу быстрее по сравнению с каждым из них в отдельности, даже с учетом затрат на передачу заказа.

Мы исследовали алгоритмы и обнаружили, что наша проблема выглядит как проблема присвоения и существует алгоритмического решения (венгерский алгоритм), но проблема в том, что классическая проблема требует «каждое задание отводится для одного работника и каждый работник назначается одного задания», а в нашем случае иногда выгоднее иметь 2 рабочих на одну работу.

То, что мы пробовали до сих пор

  1. вставьте комбинацию (упаковщик A универсальный B) в матрицу затрат, но в этом случае мы не можем добавить универсальный B в матрицу, потому что в результате мы можем получить, что универсальный B будет назначен на 2 задания (как отдельная единица и как часть комбинации с упаковщиком A)
  2. Последовательно реализуйте 2 венгерских алгоритма: сначала назначьте упаковку, затем назначьте доставку. Это работает в подавляющем большинстве случаев, но иногда приводит к неэффективным решениям. При необходимости я добавлю пример.

Сам вопрос

Я много гуглил, но не смог найти ничего, что могло бы направить меня к решению проблемы. Если у вас есть какие-либо ссылки или идеи, которые мы можем использовать в качестве ключа к решению, я буду рад их проверить.

РЕДАКТИРОВАТЬ: Я добавил решение моего вопроса с использованием грубой силы. Надеюсь, это поможет лучше понять проблему

 # constants
delivery_speed = np.array([5, 13]) # km per hour
delivery_distance = np.array([300, 2700])  # meters
flight_distance = np.array([500, 1900]) # meters время подлета
positions_amount = np.array([4, 8]) # number of positions in one order
assembly_speed = np.array([2, 3]) # minutes per position
transit_time = 5 * 60 # sec to transfer order
number_of_orders = 3 # number of orders in a batch
number_of_workers = 3 

# size of optimization matrix
matrix_size = max(number_of_workers, number_of_orders)


# maximum diagonal length for delivery and flight
max_length = np.sqrt(max(delivery_distance)**2/2)
max_flight_length = np.sqrt(max(flight_distance)**2/2)


# store positions
A = np.array([delivery_distance[1], delivery_distance[1]])
B = np.array([A[0]   max_length / 2, A[1]])

possible_order_position_x = np.array([-max_length/2, max_length])   A[0]
possible_order_position_y = np.array([-max_length, max_length])   A[1]
possible_courier_position_x = np.array([-max_flight_length/2, max_flight_length])   A[0]
possible_courier_position_y = np.array([-max_flight_length, max_flight_length])   A[1]


# generate random data 
def random_speed(speed_array):
    return np.random.randint(speed_array[0], speed_array[1] 1)

def location(possible_x, possible_y):
    return np.random.randint([possible_x[0], possible_y[0]],
                             [possible_x[1], possible_y[1]],
                             size=2)


def generate_couriers():
    # generate couriers 
    couriers = {}
    for courier in range(number_of_workers):
        couriers[courier] = {
            'position': location(possible_courier_position_x, possible_courier_position_y),
            'delivery_speed': random_speed(delivery_speed),
            'assembly_speed': random_speed(assembly_speed),
        }
    return couriers
    
couriers = generate_couriers()

store_location = {0: A, 1:B}

def generate_orders():
    # generate orders
    orders = {}
    for order in range(number_of_orders):
        orders[order] = {
            'number_of_positions': random_speed(positions_amount),
            'store_position': store_location[np.random.randint(2)],
            'customer_position': location(possible_order_position_x, possible_order_position_y)
        }
    return orders

orders = generate_orders()
orders


# functions to calculate assembly and delivery speed 
def travel_time(location_1, location_2, speed):
    # time to get from current location to store
    flight_distance = np.linalg.norm(location_1 - location_2)
    delivery_speed = 1000 / (60 * 60) * speed # meters per second
    return flight_distance / delivery_speed # seconds


def assembly_time(courier, order):
    flight_time = travel_time(courier['position'], order['store_position'], courier['delivery_speed'])
    assembly_time = courier['assembly_speed'] * order['number_of_positions'] * 60

    
    return int(flight_time   assembly_time)
assembly_time(couriers[0], orders[0])

def brute_force_solution():
    best_cte = np.inf
    best_combination = [[],[]]

    for first_phase in itertools.permutations(range(number_of_workers), number_of_orders):
        assembly_time_s = pd.Series(index = range(number_of_orders), dtype=float)
        for order, courier in enumerate(first_phase):
            assembly_time_s[order] = assembly_time(couriers[courier], orders[order]) 


        # start to work with delivery
        for second_phase in itertools.permutations(range(number_of_workers), number_of_orders):
            delivery_time_s = pd.Series(index = range(number_of_orders), dtype=float)
            for order, courier in enumerate(second_phase):
                delivery_time = travel_time(orders[order]['store_position'],
                                            orders[order]['customer_position'],
                                            couriers[courier]['delivery_speed'])
                # different cases for different deliveries
                if courier == first_phase[order]:
                    # if courier assemblied order, then deliver immidietely 
                    delivery_time_s[order] = delivery_time
                elif courier not in first_phase:
                    # flight during assembly, wait if needed, transfer time, delivery
                    flight_time = travel_time(orders[order]['store_position'],
                                              couriers[courier]['position'],
                                              couriers[courier]['delivery_speed'])
                    wait_time = max(flight_time - assembly_time_s[order], 0)
                    delivery_time_s[order] = transit_time   wait_time   delivery_time
                else: 
                    # case when shopper transfers her order and moves deliver other 
                    # check if second order is in the same store
                    first_phase_order = first_phase.index(courier)
                    if (orders[first_phase_order]['store_position'] == orders[order]['store_position']).all():
                        # transit time - fixed and happens only once! 
                        # wait, if second order has not been assemblied yet
                        # time to assembly assigned order
                        assembly_own = assembly_time_s[first_phase_order]
                        # time to wait, if order to deliver is assemblied slower
                        wait_time = max(assembly_time_s[order] - assembly_own, 0)
                        # delivery time is calculated as loop start
                        delivery_time_s[order] = transit_time   wait_time   delivery_time
                    else:
                        # transit own order - flight to the other store - wait if needed - tansit order - delivery_time
                        flight_time = travel_time(orders[first_phase_order]['store_position'],
                                                  orders[order]['store_position'],
                                                  couriers[courier]['delivery_speed'])
                        arrival_own = (assembly_time_s[first_phase_order]   transit_time   flight_time)
                        wait_time = max(assembly_time_s[order] - arrival_own, 0)
                        delivery_time_s[order] = ((transit_time * 2)   flight_time   wait_time   delivery_time)
            
            delivery_time_s = delivery_time_s.astype(int)

            # calculate and update best result, if needed
            cte = (assembly_time_s   delivery_time_s).sum()
            if cte < best_cte:
                best_cte = cte
                best_combination = [list(first_phase), list(second_phase)]
                
    return best_cte, best_combination


best_cte, best_combination = brute_force_solution()
 

Комментарии:

1. Почему бы просто не разделить каждое задание на две задачи (задача упаковщика и задача курьера) и не запустить венгерский алгоритм один раз?

2. @kaya3 вы можете объяснить, как запустить один раз? Мы не можем этого сделать, потому что мы можем заставить работника 1 выполнять работу 1, работника 2 выполнять работу 1, работника 1 работника 2 выполнять работу 1, работника 1 работника 3 выполнять работу 2. Поэтому мы получаем, что некоторые задания невозможно будет выполнить в сочетании

3. Вам нужно оптимальное решение или достаточно эвристики?

4. @Rbarryyung Сначала мы были бы довольны эвристикой, но как только наши продажи вырастут, мы захотим найти оптимальное решение и сделать его достаточно быстрым для производства

5. Это больше не проблема с назначением. Я бы начал записывать это как формальную задачу оптимизации (и решать как модель MIP/CP). Это обеспечивает хороший инструмент для экспериментов (работает ли он, оценивает решения, оценивает производительность). При необходимости позже можно разработать эвристику для повышения производительности. С помощью модели оптимизации вы можете, по крайней мере, сравнить оптимальные решения (в противном случае вы полностью в неведении относительно качества решений wrt). Если у вас нет опыта в этом, возможно, наймите студента, который поможет вам в этом.

Ответ №1:

Я провел быстрый и грязный тест с моделью, которая может работать с командами. Просто для иллюстрации.

Я создал два типа работников: тип A и тип B, а также команды, состоящие из двух работников (по одному от каждого типа). Кроме того, я создал случайные данные о затратах.

Вот частичная распечатка всех данных.

 ----     13 SET i  workers,teams

a1     ,    a2     ,    a3     ,    a4     ,    a5     ,    a6     ,    a7     ,    a8     ,    a9     ,    a10    
b1     ,    b2     ,    b3     ,    b4     ,    b5     ,    b6     ,    b7     ,    b8     ,    b9     ,    b10    
team1  ,    team2  ,    team3  ,    team4  ,    team5  ,    team6  ,    team7  ,    team8  ,    team9  ,    team10 
team11 ,    team12 ,    team13 ,    team14 ,    team15 ,    team16 ,    team17 ,    team18 ,    team19 ,    team20 
team21 ,    team22 ,    team23 ,    team24 ,    team25 ,    team26 ,    team27 ,    team28 ,    team29 ,    team30 
team31 ,    team32 ,    team33 ,    team34 ,    team35 ,    team36 ,    team37 ,    team38 ,    team39 ,    team40 
team41 ,    team42 ,    team43 ,    team44 ,    team45 ,    team46 ,    team47 ,    team48 ,    team49 ,    team50 
team51 ,    team52 ,    team53 ,    team54 ,    team55 ,    team56 ,    team57 ,    team58 ,    team59 ,    team60 
team61 ,    team62 ,    team63 ,    team64 ,    team65 ,    team66 ,    team67 ,    team68 ,    team69 ,    team70 
team71 ,    team72 ,    team73 ,    team74 ,    team75 ,    team76 ,    team77 ,    team78 ,    team79 ,    team80 
team81 ,    team82 ,    team83 ,    team84 ,    team85 ,    team86 ,    team87 ,    team88 ,    team89 ,    team90 
team91 ,    team92 ,    team93 ,    team94 ,    team95 ,    team96 ,    team97 ,    team98 ,    team99 ,    team100


----     13 SET w  workers

a1 ,    a2 ,    a3 ,    a4 ,    a5 ,    a6 ,    a7 ,    a8 ,    a9 ,    a10,    b1 ,    b2 ,    b3 ,    b4 ,    b5 
b6 ,    b7 ,    b8 ,    b9 ,    b10


----     13 SET a  a workers

a1 ,    a2 ,    a3 ,    a4 ,    a5 ,    a6 ,    a7 ,    a8 ,    a9 ,    a10


----     13 SET b  b workers

b1 ,    b2 ,    b3 ,    b4 ,    b5 ,    b6 ,    b7 ,    b8 ,    b9 ,    b10


----     13 SET t  teams

team1  ,    team2  ,    team3  ,    team4  ,    team5  ,    team6  ,    team7  ,    team8  ,    team9  ,    team10 
team11 ,    team12 ,    team13 ,    team14 ,    team15 ,    team16 ,    team17 ,    team18 ,    team19 ,    team20 
team21 ,    team22 ,    team23 ,    team24 ,    team25 ,    team26 ,    team27 ,    team28 ,    team29 ,    team30 
team31 ,    team32 ,    team33 ,    team34 ,    team35 ,    team36 ,    team37 ,    team38 ,    team39 ,    team40 
team41 ,    team42 ,    team43 ,    team44 ,    team45 ,    team46 ,    team47 ,    team48 ,    team49 ,    team50 
team51 ,    team52 ,    team53 ,    team54 ,    team55 ,    team56 ,    team57 ,    team58 ,    team59 ,    team60 
team61 ,    team62 ,    team63 ,    team64 ,    team65 ,    team66 ,    team67 ,    team68 ,    team69 ,    team70 
team71 ,    team72 ,    team73 ,    team74 ,    team75 ,    team76 ,    team77 ,    team78 ,    team79 ,    team80 
team81 ,    team82 ,    team83 ,    team84 ,    team85 ,    team86 ,    team87 ,    team88 ,    team89 ,    team90 
team91 ,    team92 ,    team93 ,    team94 ,    team95 ,    team96 ,    team97 ,    team98 ,    team99 ,    team100


----     13 SET j  jobs

job1 ,    job2 ,    job3 ,    job4 ,    job5 ,    job6 ,    job7 ,    job8 ,    job9 ,    job10,    job11,    job12
job13,    job14,    job15


----     23 SET team  composition of teams

team1  .a1 ,    team1  .b1 ,    team2  .a1 ,    team2  .b2 ,    team3  .a1 ,    team3  .b3 ,    team4  .a1 
team4  .b4 ,    team5  .a1 ,    team5  .b5 ,    team6  .a1 ,    team6  .b6 ,    team7  .a1 ,    team7  .b7 
team8  .a1 ,    team8  .b8 ,    team9  .a1 ,    team9  .b9 ,    team10 .a1 ,    team10 .b10,    team11 .a2 
team11 .b1 ,    team12 .a2 ,    team12 .b2 ,    team13 .a2 ,    team13 .b3 ,    team14 .a2 ,    team14 .b4 
team15 .a2 ,    team15 .b5 ,    team16 .a2 ,    team16 .b6 ,    team17 .a2 ,    team17 .b7 ,    team18 .a2 
team18 .b8 ,    team19 .a2 ,    team19 .b9 ,    team20 .a2 ,    team20 .b10,    team21 .a3 ,    team21 .b1 
team22 .a3 ,    team22 .b2 ,    team23 .a3 ,    team23 .b3 ,    team24 .a3 ,    team24 .b4 ,    team25 .a3 
team25 .b5 ,    team26 .a3 ,    team26 .b6 ,    team27 .a3 ,    team27 .b7 ,    team28 .a3 ,    team28 .b8 
team29 .a3 ,    team29 .b9 ,    team30 .a3 ,    team30 .b10,    team31 .a4 ,    team31 .b1 ,    team32 .a4 
team32 .b2 ,    team33 .a4 ,    team33 .b3 ,    team34 .a4 ,    team34 .b4 ,    team35 .a4 ,    team35 .b5 
team36 .a4 ,    team36 .b6 ,    team37 .a4 ,    team37 .b7 ,    team38 .a4 ,    team38 .b8 ,    team39 .a4 
team39 .b9 ,    team40 .a4 ,    team40 .b10,    team41 .a5 ,    team41 .b1 ,    team42 .a5 ,    team42 .b2 
team43 .a5 ,    team43 .b3 ,    team44 .a5 ,    team44 .b4 ,    team45 .a5 ,    team45 .b5 ,    team46 .a5 
team46 .b6 ,    team47 .a5 ,    team47 .b7 ,    team48 .a5 ,    team48 .b8 ,    team49 .a5 ,    team49 .b9 
team50 .a5 ,    team50 .b10,    team51 .a6 ,    team51 .b1 ,    team52 .a6 ,    team52 .b2 ,    team53 .a6 
team53 .b3 ,    team54 .a6 ,    team54 .b4 ,    team55 .a6 ,    team55 .b5 ,    team56 .a6 ,    team56 .b6 
team57 .a6 ,    team57 .b7 ,    team58 .a6 ,    team58 .b8 ,    team59 .a6 ,    team59 .b9 ,    team60 .a6 
team60 .b10,    team61 .a7 ,    team61 .b1 ,    team62 .a7 ,    team62 .b2 ,    team63 .a7 ,    team63 .b3 
team64 .a7 ,    team64 .b4 ,    team65 .a7 ,    team65 .b5 ,    team66 .a7 ,    team66 .b6 ,    team67 .a7 
team67 .b7 ,    team68 .a7 ,    team68 .b8 ,    team69 .a7 ,    team69 .b9 ,    team70 .a7 ,    team70 .b10
team71 .a8 ,    team71 .b1 ,    team72 .a8 ,    team72 .b2 ,    team73 .a8 ,    team73 .b3 ,    team74 .a8 
team74 .b4 ,    team75 .a8 ,    team75 .b5 ,    team76 .a8 ,    team76 .b6 ,    team77 .a8 ,    team77 .b7 
team78 .a8 ,    team78 .b8 ,    team79 .a8 ,    team79 .b9 ,    team80 .a8 ,    team80 .b10,    team81 .a9 
team81 .b1 ,    team82 .a9 ,    team82 .b2 ,    team83 .a9 ,    team83 .b3 ,    team84 .a9 ,    team84 .b4 
team85 .a9 ,    team85 .b5 ,    team86 .a9 ,    team86 .b6 ,    team87 .a9 ,    team87 .b7 ,    team88 .a9 
team88 .b8 ,    team89 .a9 ,    team89 .b9 ,    team90 .a9 ,    team90 .b10,    team91 .a10,    team91 .b1 
team92 .a10,    team92 .b2 ,    team93 .a10,    team93 .b3 ,    team94 .a10,    team94 .b4 ,    team95 .a10
team95 .b5 ,    team96 .a10,    team96 .b6 ,    team97 .a10,    team97 .b7 ,    team98 .a10,    team98 .b8 
team99 .a10,    team99 .b9 ,    team100.a10,    team100.b10


----     28 PARAMETER c  cost coefficients

               job1        job2        job3        job4        job5        job6        job7        job8        job9

a1           17.175      84.327      55.038      30.114      29.221      22.405      34.983      85.627       6.711
a2           63.972      15.952      25.008      66.893      43.536      35.970      35.144      13.149      15.010
a3           11.049      50.238      16.017      87.246      26.511      28.581      59.396      72.272      62.825
a4           18.210      64.573      56.075      76.996      29.781      66.111      75.582      62.745      28.386
a5            7.277      17.566      52.563      75.021      17.812       3.414      58.513      62.123      38.936
a6           78.340      30.003      12.548      74.887       6.923      20.202       0.507      26.961      49.985
a7           99.360      36.990      37.289      77.198      39.668      91.310      11.958      73.548       5.542
a8           22.575      39.612      27.601      15.237      93.632      42.266      13.466      38.606      37.463
a9           10.169      38.389      32.409      19.213      11.237      59.656      51.145       4.507      78.310
a10          50.659      15.925      65.689      52.388      12.440      98.672      22.812      67.565      77.678
b1           73.497       8.544      15.035      43.419      18.694      69.269      76.297      15.481      38.938
b2            8.712      54.040      12.686      73.400      11.323      48.835      79.560      49.205      53.356
b3            2.463      17.782       6.132       1.664      83.565      60.166       2.702      19.609      95.071
b4           39.334      80.546      54.099      39.072      55.782      93.276      34.877       0.829      94.884
b5           58.032      16.642      64.336      34.431      91.233      90.006       1.626      36.863      66.438
b6           49.662       4.493      77.370      53.297      74.677      72.005      63.160      11.492      97.116
b7           79.070      61.022       5.431      48.518       5.255      69.858      19.478      22.603      81.364
b8           81.953      86.041      21.269      45.679       3.836      32.300      43.988      31.533      13.477
b9            6.441      41.460      34.161      46.829      64.267      64.358      33.761      10.082      90.583
b10          40.419      11.167      75.113      80.340       2.366      48.088      27.859      90.161       1.759
team1        50.421      83.126      60.214       8.225      57.776      59.318      68.377      15.877      33.178
team2        57.624      71.983      68.373       1.985      83.980      71.005      15.551      61.071      66.155
team3         1.252       1.017      95.203      97.668      96.632      85.628      14.161       4.973      55.303
team4        34.968      11.734      58.598      44.553      41.232      91.451      21.378      22.417      54.233
team5        31.014       4.020      82.117      23.096      41.003      30.258      44.492      71.600      59.315
team6        68.639      67.463      33.213      75.994      17.678      68.248      67.299      83.121      51.517
team7         8.469      57.216       2.206      74.204      90.510      56.082      47.283      71.756      51.301
team8        96.552      95.789      89.923      32.755      45.710      59.618      87.862      17.067      63.360
team9        33.626      58.864      57.439      54.342      57.816      97.722      32.147      76.297      96.251
. . .
team98       21.277       8.252      28.341      97.284      47.146      22.196      56.537      89.966      15.708
team99       77.385      12.015      78.861      79.375      83.146      11.379       3.413      72.925      88.689
team100      11.050      20.276      21.448      27.928      15.073      76.671      91.574      94.498       7.094
(cost data for other jobs skipped)
 

Моя попытка смоделировать это как модель смешанного целочисленного программирования выглядит следующим образом:

введите описание изображения здесь

Очевидно, что это уже не проблема чистого назначения. Первое ограничение сложнее, чем мы привыкли. В нем говорится, что для каждого работника w мы можем назначить его/себя или любую команду, в которой w является членом только один раз.

Когда я решаю эту проблему без использования команд, я получаю следующее решение:

 ----     56 VARIABLE x.L  assignment

           job1        job2        job3        job4        job5        job6        job7        job8        job9

a5                                                                        1
a6                                                                                    1
b1                                    1
b3                                                1
b4                                                                                                1
b6                        1
b8                                                            1
b9            1
b10                                                                                                           1

          job10       job11       job12       job13       job14       job15

a1                                                                        1
a4                                                            1
a7                                    1
b2            1
b5                        1
b7                                                1


----     56 VARIABLE z.L                   =       59.379  total cost
 

Это стандартная проблема с назначением, но я решил ее как LP (чтобы использовать те же инструменты).

Когда я разрешаю командам, я получаю:

 ----     65 VARIABLE x.L  assignment

               job1        job2        job3        job4        job5        job6        job7        job8        job9

a1                                                                                                                1
a5                                                                            1
a6                                                                                        1
b3                                                    1
b4                                                                                                    1
b9                1
b10                                                               1
team17                                    1
team28                        1

              job10       job11       job12       job13       job14       job15

a4                                                                1
a7                                        1
b2                1
b5                            1
team86                                                                        1
team91                                                1


----     65 VARIABLE z.L                   =       40.057  total cost
 

Цель лучше (просто потому, что она может отбирать команды с низкой «стоимостью»). Также обратите внимание, что в решении ни один работник не выбирается дважды (ни индивидуально, ни в составе команды). Вот некоторый дополнительный отчет о решении, который подтверждает это:

 ----     70 SET sol  alternative solution report 

                  job1        job2        job3        job4        job5        job6        job7        job8        job9

team17.a2                                  YES
team17.b7                                  YES
team28.a3                      YES
team28.b8                      YES
-     .a1                                                                                                          YES
-     .a5                                                                      YES
-     .a6                                                                                  YES
-     .b3                                              YES
-     .b4                                                                                              YES
-     .b9          YES
-     .b10                                                         YES

                 job10       job11       job12       job13       job14       job15

team86.a9                                                                      YES
team86.b6                                                                      YES
team91.a10                                             YES
team91.b1                                              YES
-     .a4                                                          YES
-     .a7                                  YES
-     .b2          YES
-     .b5                      YES
 

Обратите внимание, что модель не очень маленькая:

 MODEL STATISTICS

BLOCKS OF EQUATIONS           3     SINGLE EQUATIONS           36
BLOCKS OF VARIABLES           2     SINGLE VARIABLES        1,801
NON ZERO ELEMENTS         6,901     DISCRETE VARIABLES      1,800
 

Однако модель MIP решается довольно легко: менее чем за секунду.

Я не тестировал модель на больших наборах данных. Это просто для того, чтобы показать, как можно подойти к подобной проблеме.

Комментарии:

1. не могли бы вы добавить библиотеки, которые вы используете для решения проблемы модели MIP?

2. Я использовал GAMS/Cplex. Но это универсальная модель MIP, поэтому подойдет любой решатель MIP (по крайней мере, для небольших экземпляров). Большие экземпляры могут потребовать немного больше размышлений.

Ответ №2:

Есть очевидная эвристика, которую вы могли бы попробовать:

  1. Решите классическую задачу с помощью венгерского алгоритма,
  2. Затем, используя пул неназначенных агентов, найдите комбинированное назначение для каждого, которое дает наибольшее улучшение.

Конечно, не оптимальный, но явное улучшение первого порядка по сравнению с одним только венгерским алгоритмом.

Комментарии:

1. у нас около 2 агентов на задание, поэтому пул неназначенных агентов может быть большим, так что предлагаемое вами решение становится дорогостоящим с точки зрения вычислений. Спасибо, еще попробую этот подход на симуляциях

2. @ArtyomAkselrod Это действительно не так дорого с точки зрения вычислений, это всего лишь дополнительная O(n^2) плата, и венгерский алгоритм уже сам O(n^3) по себе или O(n^4) поэтому он не меняет большого О.

Ответ №3:

Венгерский алгоритм-устаревшее решение, которое остается популярным по какой-то необъяснимой причине, которую я не понимаю (возможно, потому, что оно концептуально простое).

Используйте поток минимальных затрат для моделирования вашей проблемы. Он гораздо более гибкий и имеет множество эффективных алгоритмов. Это также может быть доказано для решения любой проблемы, которую может решить венгерский алгоритм (доказательство простое).

Учитывая очень расплывчатое описание вашей проблемы, вы хотели бы смоделировать базовый граф G=(V,E) с двумя слоями узлов V = (O,W), где O-заказы, а W-рабочие.

Ребра могут быть направлены, при этом каждый работник имеет ребро емкостью 1 для каждого возможного заказа. Подключите исходный узел к работнику с пропускной способностью 1 и подключите каждый узел заказа к узлу-приемнику с пропускной способностью 2 (или выше, что позволяет использовать больше работников на заказ).

То, что я описал выше, на самом деле является экземпляром maxflow, а не MCF, поскольку он не присваивает весов. Однако вы можете назначить веса любому из ребер.

Учитывая вашу формулировку проблемы, я не понимаю, как это вообще проблема с назначением, не можете ли вы использовать простую стратегию типа «первый пришел первым» (очередь), учитывая, что у вас, похоже, нет никаких критериев, по которым работник предпочитает работать над определенным заказом, а не над другим.

Комментарии:

1. извините, но у меня, очевидно, есть критерии, мне нужно оптимизировать клик, чтобы поесть, поэтому обычно наиболее предпочтителен ближайший к работе работник. Однако иногда велосипедист, находящийся на большом расстоянии от работы, может быть более эффективным, чем пеший курьер. В моей службе доставки мы получаем X заказов в минуту, и мы должны назначать наших работников на эти заказы, что на самом деле является проблемой назначения, я считаю

2. таким образом, наши расходы-это время полета (время, чтобы добраться до магазина) покупка необходимых товаров для заказов доставка. Иногда у нас есть 2 работника, назначенных для одного заказа, потому что может быть эффективно покупать товары одним работником и доставлять другим

3. Хорошо, вы очень расплывчато объясняете, как устроена ваша проблема. Если я правильно понимаю, работник может быть назначен либо водителем велосипеда, либо покупателем? Можем ли мы сказать, что эффективность (доход минус затраты) равна X с покупателем и X Y с покупателем и водителем велосипеда (т. Е. Эффект линейный)? Если эффект нелинейный, ваша проблема будет намного сложнее.