Opi1sumu
Описание задачи
Дано
одинаковых станков, которые работают параллельно и работ, котороые необходимо выполнить в произвольном порядке на всех станках. Время выполнения каждой работы на любом станке одинаково и равно одному. Для каждой работы известно время, до которого её необходимо выполнить. Необходимо успеть выполнить как можно больше работ.Описание алгоритма
Отсортируем работы в порядке невозрастания дедлайнов.
Утверждение: |
Если в оптимальном расписании можно сделать работ, то можно сделать первые работ. |
Пусть в оптимальном расписании были сделаны работы Тогда, если заменить во всём расписании работу . Докажем, что существует оптимальное расписание, в котором сделаны работы . Пусть работы тоже отсортированы в порядке неубывания дедлайна. Тогда . на работу , то она, тем более, будет выполнена. |
Определение: |
Обозначим за тайм-слот t множество из не более, чем | различных чисел — номера работ, которые мы хотим выполнить в момент времени .
Введем тайм-слот для каждого момента времени от до .
Каждую работу будем пытаться сделать как можно позже. Будем рассматривать работы в порядке невозрастания дедлайнов.
-ю работу попытаемся добавить в тайм-слоты с номерами от по .
После добавления некоторые тайм-слоты могли переполниться (тайм-слот переполнился, если в нём уже находилось
работ, и в него добавили -ю).
Для переполнившегося тайм-слота найдём найдем самый правый левее него тайм-слот, который ещё не переполнился и перекинем работу,
которой там еще нет, в него. Так как в нем меньше элементов, то, по принципу Дирихле, это можно сделать.
Утверждение: |
Следуя этому алгоритму, расписания не существует тогда и только тогда, когда
переполнился нулевой тайм-слот. |
Расписания не существует, а значит, никакой алгоритм его не найдет. Пусть при добавлении -й работы произошло переполнение нулевого тайм-слота. Рассмотрим алгоритм добавления в тайм-слоты: работа добавляется в тайм-слоты , после чего из переполнившихся работы перебрасываются в более ранние. Временно разрешим хранить в тайм-слоте сколь угодно много работ: отменим перебрасывание. Посмотрим на то, что получилось. Так как работу нельзя выполнять одновременно на двух станках, то ни одну единицу работы отсрочить нельзя. Будем рассматривать тайм-слоты в порядке уменьшения времени. Если в очередном тайм-слоте в данный момент больше, чем работ, то остаток нужно перекинуть на какие-то более ранние тайм-слоты. Заметим, что выгоднее перекинуть на наиболее поздние тайм-слоты: более ранние тайм-слоты могут понадобиться для перекидываний с тайм-слотов, идущих раньше просматриваемого. .Также заметим, что алгоритм перекидывания работ таков, что итоговое распределение количеств работ в соответствующих тайм-слотах не зависит от того, в каком порядке обрабатывались переполнившиеся тайм-слоты. При рассмотрении очередного переполнившегося тайм-слота мы необходимо должны куда-то перекинуть несколько работ из него. Так как перекидывание происходит в тайм-слот с наибольшим допустимым временем, то то, что неоходимо перекинуть что-то из нулевого, влечет то, что не существует расписания, в котором можно успеть выполнить все эти работы |
Опираясь на это утверждение, можно найти максимальное количество работ, которое можно выполнить. Обозначим его за
.Сведем задачу построения распинания по построенным тайм-слотам к задаче о покрытии двудольного графа минимальным количеством паросочетаний.
Построим двудольный граф. В левой доле вершинам будут соответствовать работы, в правой — времена. Соответственно, в левой доле будет
вершин, в правой — . Ребро между работой и временем будет, если работа есть в тайм-слоте .Рассмотрим какое-то паросочетание
в этом графе. Оно соответствует корректному расписанию работ на одной машине: ни одна работа не выполняется два раза, и ни в один момент времени не выполняется более одной работы.Тогда, если мы сможем построить множество мощности
такое, что каждое ребро находится хотя бы в одном из паросочетаний, то оно будет соответствовать тому, что каждая работа обработана на каждом станке, а значит, составлено корректное расписание для этих работ.Достроим граф до регулярного степени
. Достраивать будем следующим образом. Каждая вершина в левой доле имеет степень , так как каждая работа представлена в тайм-слотах. В правой доле степень каждой вершины не больше , так как в тайм-слоте не может быть больше, чем работ. Значит, в левой доле не больше вершин, чем в правой. Добавим в левую долю фиктивных вершин, чтобы количества вершин в левой и правой долях сравнялись. После чего просто будем добавлять ребра между вершинами, степень которых еще меньше . Для покрытия этого графа паросочетаниями воспользуемся тем фактом, что регулярный двудольный граф степени можно покрыть паросочетаниями.При помощи построения паросочетаний было построено расписание для тех
работ, которые можно успеть сделать. Так как остальные работы уже нельзя успеть, расписание для них можно составить произвольное. Например, выполнять их по очереди после выполнения первых работ.Оценка сложности алгоритма
Рассмотрим добавление очередной работы в тайм-слоты. За
найдём переполнившийся тайм-слот и за перекинем из него элемент. Так как , итоговая сложность этой части — .Достроение графа до регулярного делается за
, где — количество ребер в нем. Количество ребер в регулярном двудольном графе , где — количество вершин в одной из долей, а — степень. Количество вершин в правой доле — . Значит, граф будет построен за , так как степень каждой вершины — .Сложность последней фазы зависит от того, каким алгоритмом граф разбивается на паросочетания. Использовав, например, алгоритм Куна, можно добиться сложности
. Итоговая сложность алгоритма — .