Какой алгоритм для назначения сдвигов (задача дискретной оптимизации)

Я разрабатываю приложение, которое оптимально присваивает смены медсестрам в больнице. Я считаю, что это проблема linear programming с дискретными переменными и, следовательно, вероятно, NP-hard:

  • В течение каждого дня каждой медсестре (примерно 15-20) присваивается сдвиг
  • Существует небольшое число (около 6) разных сдвигов
  • Существует значительное количество ограничений и критериев оптимизации, касающихся дня или относительно emplyoee, например:
    • Каждый день должно быть минимальное количество людей, назначенных на каждую смену.
    • Некоторые смены перекрываются, так что это нормально, если у кого-то меньше людей в начале смены, если кто-то делает промежуточный сдвиг
    • Некоторые люди предпочитают раннюю смену, некоторые предпочитают позднюю смену, но минимум изменений сдвига требуется, чтобы получить более высокую зарплату смены.
    • Не допускается, чтобы один человек работал с задержкой в ​​один день и с ранней сменой на следующий день (из-за минимальных правил времени отдыха).
    • Встреча с назначенными рабочими неделями (разные для разных людей)
    • ...

Таким образом, в основном существует большое число (от 20 * 30 = 600) переменных, каждое из которых может принимать небольшое число дискретных значений.

В настоящее время я планирую использовать измененный алгоритм Min-conflict

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

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

Изменить: нет необходимости находить строго оптимальное решение; список в настоящее время выполнен вручную, и я уверен, что результат значительно неоптимальный в большинстве случаев - не должно быть трудно превзойти его. Краткосрочные корректировки и ручные переопределения также обязательно понадобятся, но я не считаю, что это будет проблемой; Пометка прошлых и ручных назначений как "фиксированная" должна фактически упростить задачу, уменьшив пространство решения.

Ответ 1

Это сложная проблема, которая хорошо решается. Было много научных работ по этому вопросу, особенно в разделе Operations Research - см., Например, справочные материалы для медсестер 2007-2008 гг. или только google "исследование операций по регистрации медсестер". Сложность также зависит от таких аспектов, как: сколько дней нужно решить; какой тип "запросов" может сделать медсестра; является реестром "циклический"; это долгосрочный план или он должен обрабатывать краткосрочный "ремонт", например, болезнь и свопы и т.д. и т.д.

Алгоритм, который вы описываете, - это heuristic. Вы можете обнаружить, что вы можете настроить его, чтобы он работал хорошо для одного конкретного примера проблемы, но как только "что-то" изменилось, оно может работать не так хорошо (например, локальная оптимизация, плохая конвергенция).

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

Ответ 2

Умм, ты знал, что некоторые ИЛП-решатели неплохо справляются? Попробуйте AIMMS, Mathematica или комплект программирования GNU! 600 Variables - это, конечно, намного больше, чем теорема Ленстра, которая будет легко решена, но иногда у этих решателей ILP есть хорошая ручка, а в AIMMS вы можете немного изменить стратегию ветвления. Кроме того, существует действительно быстрое 100% -приближение для ILP.

Ответ 3

Я решил проблему назначения смены для крупного завода по производству в последнее время. Сначала мы попробовали генерировать чисто случайные графики и возвращать любой, прошедший тест is_schedule_valid - алгоритм резервного копирования. Это было, конечно, медленным и неопределенным.

Далее мы попытались использовать генетические алгоритмы (как вы сказали), но не смогли найти хорошую функцию фитнеса, которая закрывалась на любом жизнеспособном решении (поскольку наименьшее изменение может сделать все расписание ПРАВИЛЬНО или НЕПРАВИЛЬНО - никаких точек для почти).

Наконец, мы выбрали следующий метод (который отлично поработает!):

  • Рандомизируйте набор входных данных (т.е. задания, сдвиг, персонал и т.д.).
  • Создайте правильный кортеж и добавьте его в предварительный график.
  • Если не удалось создать правильный кортеж, откат (и увеличение) последнего добавленного кортежа.
  • Передайте частичное расписание функции, которая проверяет could_schedule_be_valid, то есть может ли это расписание быть действительным, если оставшиеся кортежи были заполнены возможным способом.
  • Если !could_schedule_be_valid, просто откат (и увеличение) кортеж, добавленный в (2).
  • Если schedule_is_complete, return schedule
  • Перейти (2)

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

Удачи. Мы потратили дни, пробовав первые два алгоритма, но получили рекомендуемый алгоритм, генерирующий действительные расписания моментально за 5 часов разработки.

Кроме того, мы поддерживали предварительную фиксацию и пост-фиксацию присвоений, которые соблюдал бы алгоритм. Вы просто не рандомизировали эти слоты на шаге 1. Вы обнаружите, что решения не должны быть нигде близкими к оптимальным. Наше решение O (N * M) как минимум, но выполняется в PHP (!) Менее чем за полсекунды для всей производственной фабрики. Красота быстро устраняет плохие графики, используя хороший тест could_schedule_be_valid.

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

Ответ 4

Майк,

Не знаю, если у вас есть хороший ответ на это, но я уверен, что программирование ограничений - это билет. В то время как GA может дать вам ответ, CP разработан, чтобы дать вам много ответов или сказать вам, если нет приемлемого решения. Поиск по "программированию ограничения" и составлению расписания должен содержать много информации. Это относительно новая область и методы CP хорошо работают на многих типах проблем, где традиционные методы оптимизации боятся.

Ответ 6

Одна вещь, которую вы можете сделать, - попытаться найти симметрии в проблеме. Например. можете ли вы рассматривать всех медсестер как эквивалент для целей проблемы? Если это так, то вам нужно только рассмотреть медсестер в каком-то произвольном порядке - вы можете избежать рассмотрения решений, чтобы любая медсестра я была запланирована перед любой медсестрой j, где i > j. (Вы сказали, что отдельные медсестры предпочитают времена смены, что противоречит этому примеру, хотя, возможно, это менее важная цель?)

Ответ 7

Я думаю, вы должны использовать генетический алгоритм, потому что:

Также посмотрите на аналогичный вопрос и другой

Ответ 8

Используя программирование CSP, я разработал программы для автоматического резервного копирования shitfs. например:

  • система с 2-мя сдвигами - протестирована для более 100 медсестер, 30-дневного горизонта, 10+ правила
  • Система с 3-мя сдвигами - проверена для 80+ медсестер, 30-дневного горизонта, 10+ правил.
  • 3-х секундная система, 4 команды - проверено на горизонт 365 дней, 10+ правил,

и несколько аналогичных систем. Все они были протестированы на моем домашнем ПК (1,8 ГГц, двухъядерный). Время выполнения всегда было приемлемым, т.е. для 3/потребовалось около 5 минут и 300 МБ ОЗУ.

Самая сложная часть этой проблемы заключалась в выборе правильного решателя и правильной стратегии решения.