В прошлый раз, мы рассмотрели пример одной задачи, которую можно решить методами оптимизации. Напомним, что для применения оптимизации должны выполняться два основных требования: наличие целевой функции и тот факт, что близкие параметры дают близкие решения. Не каждую задачу, удовлетворяющую этим требованиям, можно решить методами оптимизации, но есть неплохие шансы, что попытка применить эти методы даст интересные результаты, о которых вы даже не подозревали.
На этот раз, мы займемся другой задачей, для которой оптимизация просто напрашивается. Общая формулировка такова: распределить ограниченные ресурсы между людьми, у которых есть явно выраженные предпочтения, так чтобы все были максимально счастливы (или, в зависимости от склада характера, минимально недовольны))))
Оптимизация распределения студентов по комнатам
Сегодня мы решим задачу о распределении студентов по комнатам в общежитии с учетом их основного и альтернативного пожеланий. Хотя формулировка довольно специфична, ее можно легко обобщить на похожие задачи, – тот же самый код годится для распределения игроков по столам в онлайновой карточной игре, для распределения ошибок между разработчиками в большом программном проекте и даже для распределения работы по дому между прислугой. Как и раньше, наша цель – собрать информацию об отдельных людях и найти такое сочетание, которое приводит к оптимальному результату.# Двухместные комнаты dorms = ['Zeus','Athena','Hercules','Bacchus','Pluto'] # Люди и два пожелания у каждого (основное, второстепенное) prefs = [('Toby', ('Bacchus', 'Hercules')), ('Steve', ('Zeus', 'Pluto')), ('Karen', ('Athena', 'Zeus')), ('Sarah', ('Zeus', 'Pluto')), ('Dave', ('Athena', 'Bacchus')), ('Jeff', ('Hercules', 'Pluto')), ('Fred', ('Pluto', 'Athena')), ('Suzie', ('Bacchus', 'Hercules')), ('Laura', ('Bacchus', 'Hercules')), ('James', ('Hercules', 'Athena'))]
Представление решения
В каждой комнате должно оказаться ровно два студента. Будем считать, что в каждой комнате есть два отсека, то есть всего их в нашем случае будет десять. Каждому студенту по очереди назначается один из незанятых отсеков; первого можно поместить в любой из десяти отсеков, второго – в любой из оставшихся девяти и т. д.
Область определения для поиска (смотри предыдущую статью):
# [9, 8, 7, 6,..., 1] domain = [i for i in xrange(9, 0, -1)]
Целевая функция
Целевая функция работает следующим образом. Создается начальный список отсеков, и уже использованные отсеки из него удаляются. Стоимость вычисляется путем сравнения комнаты, в которую студент помещен, с двумя его пожеланиями. Стоимость не изменяется, если студенту досталась та комната, в которую он больше всего хотел поселиться; увеличивается на 1, если это второе из его пожеланий; и увеличивается на 3, если он вообще не хотел жить в этой комнате.def dorm_cost(vec): cost=0 # Создаем список отсеков, т.е. первые 2 места - 0 отсек и т.д. slots = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4] # Цикл по студентам, i - порядковый номер студента for i in xrange(len(vec)): x = int(vec[i]) dorm = dorms[slots[x]] pref = prefs[i][1] print x, '->', slots[x],'->', prefs[i][0], pref, '->', dorm # Стоимость основного пожелания равна 0, альтернативного – 1 # Если комната не входит в список пожеланий, стоимость увеличивается на 3 if pref[0] == dorm: cost += 0 elif pref[1] == dorm: cost += 1 else: cost += 3 # Удалить выбранный отсек # Это самое важное действие тут, # прошу особо обратить на него внимание и учесть, что элементы сдвигаются del slots[x] return cost
Оптимизация
Всем кто не изучил методы оптимизации в предыдущей статье, бегом изучать!) Хорошим мальчикам и может даже девочкам, импортировать любой из методов и запустить!) Я, для примера, попробую на генетическом алгоритме.
result, score = genetic_optimize(domain, dorm_cost) print result, score
Например у меня, нашелся такой результат [7, 1, 2, 0, 0, 1, 2, 1, 0] 1, что соответствует следующему выводу:
7 -> 3 -> Toby ('Bacchus', 'Hercules') -> Bacchus
1 -> 0 -> Steve ('Zeus', 'Pluto') -> Zeus
2 -> 1 -> Karen ('Athena', 'Zeus') -> Athena
0 -> 0 -> Sarah ('Zeus', 'Pluto') -> Zeus
0 -> 1 -> Dave ('Athena', 'Bacchus') -> Athena
1 -> 2 -> Jeff ('Hercules', 'Pluto') -> Hercules
2 -> 4 -> Fred ('Pluto', 'Athena') -> Pluto
1 -> 3 -> Suzie ('Bacchus', 'Hercules') -> Bacchus
0 -> 2 -> Laura ('Bacchus', 'Hercules') -> Hercules
Т.е. не устроило только Lauru и то, учтен был ее 2й вариант)
Вместо вывода
Итак, надеюсь, я показал, что используя одни алгоритмы, но меняя область определения и принцип расчета целевой функции, мы можем решить абсолютно разные оптимизационные задачи!)
Комментариев нет:
Отправить комментарий