Максимизация комбинации ряда значений

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

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

Итак, что я имею:

  • Список 12 дат
  • Список 18 студентов
  • CSV-файл, где каждый студент (строка) имеет оценку 1-5 для каждой даты

Что бы я хотел получить:

  • Каждый студент должен иметь одну из презентаций типа А (intro), один из типа представления B (figures) и 3 презентации типа С (aims)
  • Каждая дата должна иметь как минимум 1 презентацию каждого типа
  • Каждая дата должна содержать не более 2-х типов А или В
  • Попробуйте дать студентам презентации, которые они высоко оценили (4 или 5)

Должен заметить, что я понимаю, что это похоже на домашнее задание, но это настоящая жизнь:-). Я думал, что я мог бы сделать Student класс для каждого студента, который содержит даты для каждого типа презентации, но я не был уверен, каков будет лучший способ его заполнения. На самом деле, я даже не уверен, с чего начать.

1 ответ

Решение

TL; DR: я думаю, что вы предоставляете своим студентам слишком большой выбор:D

Но я все равно попытался решить эту проблему. Довольно забавное упражнение на самом деле, хотя некоторые ограничения были немного расплывчаты. Больше всего мне пришлось угадывать, как будет выглядеть фактическое распределение предпочтений студентов. Я пошел с равномерно распределенными, независимыми переменными, хотя это, вероятно, не очень реалистично. Тем не менее, я думаю, что он должен работать так же хорошо, как и с моими случайно сгенерированными данными.

Я подумал о грубом форсировании, но приблизительный анализ дал мне оценку более 10^65 возможных конфигураций. Это довольно много. И поскольку у нас нет триллиона триллионов лет, чтобы рассмотреть все из них, нам понадобится эвристический подход.

Из-за масштабов проблемы я старался не возвращаться назад. Но это означало, что вы могли застрять; не может быть решения, в котором все получают только даты, которые они дали 4 и 5.

Я закончил тем, что реализовал двусторонний Итеративный Поиск, подобный углубленному, где и лучший вариант, на который мы все еще надеемся (т. Е. Назначаем студентам дату, которую они дали 5), и сценарий наихудшего случая, на который мы готовы принять (некоторые студенты, возможно, придется жить с 3) постепенно снижаются, пока не будет найдено решение. Если мы застряли, перезагрузите, понизьте ожидания и попробуйте снова. Задачи A и B назначаются первыми, а C выполняется только после того, как A и B завершены, поскольку ограничения на C гораздо менее строгие.

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

В настоящее время кажется, что можно найти решение практически для каждого случайного набора предпочтений. Я включил оценку метрики; соотношение между суммой значений предпочтений всех назначенных комбинаций "студент / дата" и суммой всех значений "идеал студента / топ-3". Например, если у студента X было две пятерки, одна четверка и остальные три в его списке, и он назначен одной из его пятерок и двух тройок, он получает 5+3+3=11, но в идеале мог бы получить 5+5+4=14; он 11/14 = 78,6% удовлетворен.

После некоторого тестирования кажется, что моя реализация имеет тенденцию приносить среднему удовлетворению студента около 95%, что намного лучше, чем я ожидал:) Но опять же, это с поддельными данными. Реальные предпочтения, вероятно, более сложны, и их сложнее удовлетворить.

Ниже приводится ядро ​​алгоритма. Полный сценарий составляет ~250 строк, и я думаю, что он слишком длинный. Проверьте это на Github.

...

# Assign a date for a given task to each student, 
# preferring a date that they like and is still free.
def fill(task, lowest_acceptable, spread_weight=0.1, tasks_to_spread="ABC"):
        random_order = range(nStudents) # randomize student order, so everyone
        random.shuffle(random_order)    # has an equal chance to get their first pick
        for i in random_order:
            student = students[i]
            if student.dates[task]: # student is already assigned for this task?
                continue

            # get available dates ordered by preference and how fully booked they are
            preferred = get_favorite_day(student, lowest_acceptable,  
                                         spread_weight, tasks_to_spread)
            for date_nr in preferred:
                date = dates[date_nr]
                if date.is_available(task, student.count, lowest_acceptable == 1):
                    date.set_student(task, student.count)
                    student.dates[task] = date
                    break

# attempt to "fill()" the schedule while gradually lowering expectations
start_at = 5
while start_at > 1:
    lowest_acceptable = start_at
    while lowest_acceptable > 0:
        fill("A", lowest_acceptable, spread_weight, "AAB")
        fill("B", lowest_acceptable, spread_weight, "ABB")
        if lowest_acceptable == 1:
            fill("C", lowest_acceptable, spread_weight_C, "C")
        lowest_acceptable -= 1

И вот пример результата, напечатанного скриптом:

                                      Date                                      
================================================================================
Student |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  |  10 |  11 |  12 |
================================================================================
   1    |     |  A  |  B  |     |  C  |     |     |     |     |     |     |     |
   2    |     |     |     |     |  A  |     |     |     |     |  B  |  C  |     |
   3    |     |     |     |     |  B  |     |     |  C  |     |  A  |     |     |
   4    |     |     |     |  A  |     |  C  |     |     |     |     |     |  B  |
   5    |     |     |  C  |     |     |     |  A  |  B  |     |     |     |     |
   6    |     |  C  |     |     |     |     |     |     |  A  |  B  |     |     |
   7    |     |     |  C  |     |     |     |     |  B  |     |     |     |  A  |
   8    |     |     |  A  |     |  C  |     |  B  |     |     |     |     |     |
   9    |  C  |     |     |     |     |     |     |     |  A  |     |     |  B  |
   10   |  A  |  B  |     |     |     |     |     |     |  C  |     |     |     |
   11   |  B  |     |     |  A  |     |  C  |     |     |     |     |     |     |
   12   |     |     |     |     |     |  A  |  C  |     |     |     |  B  |     |
   13   |  A  |     |     |  B  |     |     |     |     |     |     |     |  C  |
   14   |     |     |     |     |  B  |     |     |     |  C  |     |  A  |     |
   15   |     |     |  A  |  C  |     |  B  |     |     |     |     |     |     |
   16   |     |     |     |     |     |  A  |     |     |     |  C  |  B  |     |
   17   |     |  A  |     |  C  |     |     |  B  |     |     |     |     |     |
   18   |     |     |     |     |     |     |  C  |  A  |  B  |     |     |     |
================================================================================
Total student satisfaction: 250/261 = 95.00%
Другие вопросы по тегам