Методы решения задач теории расписаний — различия между версиями
(→Жадное построение расписания) |
(→Сведение к другой задаче) |
||
| Строка 2: | Строка 2: | ||
При сведении текущей задачи теории расписаний <tex> S </tex> к какой-то другой <tex> S' </tex>(не обязательно задаче теории расписаний) необходимо доказать два пункта: | При сведении текущей задачи теории расписаний <tex> S </tex> к какой-то другой <tex> S' </tex>(не обязательно задаче теории расписаний) необходимо доказать два пункта: | ||
# Допустимость расписания, построенного с помощью задачи <tex> S' </tex>, или существование способа его трансформации в допустимое без нарушения оптимальности. | # Допустимость расписания, построенного с помощью задачи <tex> S' </tex>, или существование способа его трансформации в допустимое без нарушения оптимальности. | ||
| − | # Следствие того, что если мы оптимизируем <tex> S' </tex>, мы также оптимизируем ответ для <tex> S </tex> | + | # Следствие того, что если мы оптимизируем <tex> S' </tex>, мы также оптимизируем ответ для <tex> S </tex>. |
Примечание — если требуется полиномиальное время для решения задачи, требуется, чтобы сведение к другой задаче и трансформация расписания в допустимое также происходили за полиномиальное время. | Примечание — если требуется полиномиальное время для решения задачи, требуется, чтобы сведение к другой задаче и трансформация расписания в допустимое также происходили за полиномиальное время. | ||
| + | |||
| + | * Задачи класса Open Shop при условии <tex>p_{ij}=1</tex>, сводятся к задачам равной длительности на параллельных станках. | ||
| + | * Задачи класса Flow Shop при условии <tex>p_{ij}=1</tex>, сводятся к задаче на одном станке. | ||
| + | * Часто в задачах, в которых допускаются прерывания, оптимальный ответ совпадает с соответствующими задачами без прерываний: | ||
| + | ** <tex> P \mid pmtn \mid \sum w_i C_i </tex> | ||
| + | ** <tex> F2 \mid pmtn \mid C_{max} </tex> | ||
| + | |||
=== Примеры === | === Примеры === | ||
==== 1 | intree | Sum(w_i C_i) ==== | ==== 1 | intree | Sum(w_i C_i) ==== | ||
| Строка 18: | Строка 25: | ||
==== R || Sum(C_i) ==== | ==== R || Sum(C_i) ==== | ||
| − | В этой задаче дано <tex> n </tex> работ и <tex> m </tex> | + | В этой задаче дано <tex> n </tex> работ и <tex> m </tex> станков, причем для каждого станка длительность выполнения на нем <tex>i</tex>-й работы своя и равна <tex> p_{ij} </tex>. |
| − | Рассмотрим произвольное допустимое расписание для этой задачи. Рассмотрим какую-то | + | Рассмотрим произвольное допустимое расписание для этой задачи. Рассмотрим какую-то станок <tex> j </tex>, пусть на нем выполняется <tex>n_j</tex> работ. Тогда вклад этого станка в целевую функцию (не теряя общности, пронумеруем работы на этом станке от <tex>1 </tex> до <tex>n_j</tex>) рассчитывается как: |
<tex> \sum\limits_{i=1}^{n_j} (p_ij + \sum\limits_{q=1}^{i-1} p_qj) = n_j p_{1j} + (n_j - 1) p_{2j} + \dots + 2 p_{(n_j-1)j} + p_{n_jj} </tex> | <tex> \sum\limits_{i=1}^{n_j} (p_ij + \sum\limits_{q=1}^{i-1} p_qj) = n_j p_{1j} + (n_j - 1) p_{2j} + \dots + 2 p_{(n_j-1)j} + p_{n_jj} </tex> | ||
| Строка 26: | Строка 33: | ||
Заметим, что в каждом допустимом расписании перед каждой работой окажется коэффициент <tex> k </tex>, означающий, что соответствующая работа выпллняется <tex> k </tex>-й с конца. Понятно, что в различных расписаниях <tex> k </tex> может принимать значения от <tex>1</tex> до <tex>n</tex>. | Заметим, что в каждом допустимом расписании перед каждой работой окажется коэффициент <tex> k </tex>, означающий, что соответствующая работа выпллняется <tex> k </tex>-й с конца. Понятно, что в различных расписаниях <tex> k </tex> может принимать значения от <tex>1</tex> до <tex>n</tex>. | ||
| − | Сведем задачу к назначению каждой работы <tex> i </tex> позиции с конца <tex> k </tex> на | + | Сведем задачу к назначению каждой работы <tex> i </tex> позиции с конца <tex> k </tex> на станке <tex> j </tex> с помощью задачи [[Поток минимальной стоимости | mincost-maxflow]]. Поместим в левую долю графа работы, в правую долю — пары из станка и коэффициента и проведем соответствующие ребра пропускной способности <tex>1</tex> и стоимости <tex>k p_{ij}</tex>, соответствующие вкладу работы в целевую функцию, если она окажется в позиции <tex> k </tex> с конца на станке <tex> j </tex>. Проведем из стока в левую долю ребра стоимости <tex>0</tex> и пропускной способности <tex>1</tex>, из правой доли в сток — также ребра стоимости <tex> 0 </tex> и пропускной способности <tex>1</tex>. Найдем в этой сети максимальный поток минимальной стоимости. Утверждается, что если ребро <tex> i \to (j, k) </tex> насыщено потоком, то работа <tex> i </tex> в оптимальном расписании должна стоять на станке <tex> j </tex> в позиции <tex> k </tex> с конца. |
# Целевые функции задачи mincost-maxflow и текущей задачи совпадают, так как у ребер между долями пропускная способность 1, а у дополнительных ребер из истока и в сток нулевая стоимость, и они не могут внести вклад в целевую функцию. | # Целевые функции задачи mincost-maxflow и текущей задачи совпадают, так как у ребер между долями пропускная способность 1, а у дополнительных ребер из истока и в сток нулевая стоимость, и они не могут внести вклад в целевую функцию. | ||
| Строка 37: | Строка 44: | ||
Докажем, что оптимальный ответ для <tex> S </tex> равен оптимальному ответу к задаче <tex>S' = P \mid p_i=m, pmtn \mid \sum w_i C_i </tex>, где прерывания позволено делать только в целые моменты времени. | Докажем, что оптимальный ответ для <tex> S </tex> равен оптимальному ответу к задаче <tex>S' = P \mid p_i=m, pmtn \mid \sum w_i C_i </tex>, где прерывания позволено делать только в целые моменты времени. | ||
# Целевые функции задач совпадают, поэтому из оптимальности <tex> S' </tex> следует оптимальность <tex> S </tex>. | # Целевые функции задач совпадают, поэтому из оптимальности <tex> S' </tex> следует оптимальность <tex> S </tex>. | ||
| − | # Покажем, как получить из расписания <tex> S' </tex> допустимое расписание для <tex>S</tex> (в расписании для <tex>S'</tex> допустимость нарушает то, что на | + | # Покажем, как получить из расписания <tex> S' </tex> допустимое расписание для <tex>S</tex> (в расписании для <tex>S'</tex> допустимость нарушает то, что на одном станке выполняется несколько блоков одной работы): |
## Построим двудольный граф, в левую долю которого поместим работы, а в правую — возможные моменты времени. Из вершины, соответствующей работе <tex> i </tex> будет идти ребро в вершину, соответствующую временному моменту <tex> t</tex>, если работа <tex> i </tex> в расписании для <tex> S' </tex> претендует на выполнение в момент времени <tex>t</tex>. | ## Построим двудольный граф, в левую долю которого поместим работы, а в правую — возможные моменты времени. Из вершины, соответствующей работе <tex> i </tex> будет идти ребро в вершину, соответствующую временному моменту <tex> t</tex>, если работа <tex> i </tex> в расписании для <tex> S' </tex> претендует на выполнение в момент времени <tex>t</tex>. | ||
## Раскрасим ребра этого графа в <tex>m</tex> цветов, из теории графов известно, что это можно сделать. | ## Раскрасим ребра этого графа в <tex>m</tex> цветов, из теории графов известно, что это можно сделать. | ||
| − | ## Назначим выполнение единичного элемента работы <tex>i</tex> в момент времени <tex>t</tex> на | + | ## Назначим выполнение единичного элемента работы <tex>i</tex> в момент времени <tex>t</tex> на станке <tex>k</tex>, если соответствующее ребро раскрашено в цвет <tex>k</tex>. |
| − | ## После данного преобразования мы не изменим значение целевой функции (так как мы переставляем только элементы работ, выполняющихся в один и тот же момент времени). Также расписание станет допустимым для <tex> S </tex>, так как по определению реберной раскраски, не будет ни одной работы, два единичных блока которых выполняется на | + | ## После данного преобразования мы не изменим значение целевой функции (так как мы переставляем только элементы работ, выполняющихся в один и тот же момент времени). Также расписание станет допустимым для <tex> S </tex>, так как по определению реберной раскраски, не будет ни одной работы, два единичных блока которых выполняется на одном станке и во все моменты времени не окажется того, что на один станок назначено две работы. |
| − | Чтобы непосредственно решить эту задачу, воспользуемся теоремой о том, что для задачи <tex> P \mid p_i=m, pmtn \mid \sum w_i C_i </tex> существует оптимальное расписание без прерываний<ref>P. Brucker. Scheduling Algorithms (2006), 5th edition, p. 121 </ref>. Известно, что для того, чтобы получить оптимальное расписание для такой задачи без прерываний, надо помещать работы по очереди на | + | Чтобы непосредственно решить эту задачу, воспользуемся теоремой о том, что для задачи <tex> P \mid p_i=m, pmtn \mid \sum w_i C_i </tex> существует оптимальное расписание без прерываний<ref>P. Brucker. Scheduling Algorithms (2006), 5th edition, p. 121 </ref>. Известно, что для того, чтобы получить оптимальное расписание для такой задачи без прерываний, надо помещать работы по очереди на станки <tex>1 \dots m </tex> в порядке убывания весов. Длительности у всех работ совпадают, поэтому расписание будет состоять из <tex> \lfloor \frac{n}{m} \rfloor </tex> блоков по <tex> m </tex> работ и, возможно, одного неполного блока из <tex> n \mod m </tex> работ. Таким образом, аналогично задаче <tex> O \mid p_{ij}=1 \mid C_{max}</tex>, чтобы получить допустимое расписание, можно не строить раскраску графа, а просто циклически сдвигать последовательности работ внутри каждого блока, что позволяет достичь асимптотики <tex> O(m n) </tex>. |
| − | |||
| − | |||
== Построение расписания по нижней оценке == | == Построение расписания по нижней оценке == | ||
Версия 00:02, 4 мая 2012
Содержание
Сведение к другой задаче
При сведении текущей задачи теории расписаний к какой-то другой (не обязательно задаче теории расписаний) необходимо доказать два пункта:
- Допустимость расписания, построенного с помощью задачи , или существование способа его трансформации в допустимое без нарушения оптимальности.
- Следствие того, что если мы оптимизируем , мы также оптимизируем ответ для .
Примечание — если требуется полиномиальное время для решения задачи, требуется, чтобы сведение к другой задаче и трансформация расписания в допустимое также происходили за полиномиальное время.
- Задачи класса Open Shop при условии , сводятся к задачам равной длительности на параллельных станках.
- Задачи класса Flow Shop при условии , сводятся к задаче на одном станке.
- Часто в задачах, в которых допускаются прерывания, оптимальный ответ совпадает с соответствующими задачами без прерываний:
Примеры
1 | intree | Sum(w_i C_i)
Предположим, что мы уже умеем решать задачу [1]. Сведем нашу задачу к ней следующим образом:
- Развернем все ребра, теперь если работа зависела от работы , работа будет зависеть от .
- Заменим все стоимости на противоположные .
Утверждается, что решив соответствующую задачу и развернув полученное расписание, мы получим ответ для текущей задачи.
- Полученное расписание будет допустимым, так как расписание для было допустимым, и в нем никакие две работы не пересекались и не прерывались. Развернув, мы не могли нарушить это свойство. Также из-за того, что мы развернули расписание, мы добились того, что все работы выполняются в правильном порядке (в расписании для из-за того, что все ребра были развернуты, порядок был нарушен для всех работ). Таким образом, получили что расписание — допустимое.
- Пусть с помощью задачи мы получили последовательность работ . Распишем по определению значение целевой функции для :
- Заметим, что первое слагаемое соответствует целевой функции для последовательности , а второе и третье слагаемые — константы, зависящие только от входных данных и не зависящие от перестановки работ. Таким образом, оптимальное значение для также минимизирует , ч.т.д.
R || Sum(C_i)
В этой задаче дано работ и станков, причем для каждого станка длительность выполнения на нем -й работы своя и равна .
Рассмотрим произвольное допустимое расписание для этой задачи. Рассмотрим какую-то станок , пусть на нем выполняется работ. Тогда вклад этого станка в целевую функцию (не теряя общности, пронумеруем работы на этом станке от до ) рассчитывается как:
Заметим, что в каждом допустимом расписании перед каждой работой окажется коэффициент , означающий, что соответствующая работа выпллняется -й с конца. Понятно, что в различных расписаниях может принимать значения от до .
Сведем задачу к назначению каждой работы позиции с конца на станке с помощью задачи mincost-maxflow. Поместим в левую долю графа работы, в правую долю — пары из станка и коэффициента и проведем соответствующие ребра пропускной способности и стоимости , соответствующие вкладу работы в целевую функцию, если она окажется в позиции с конца на станке . Проведем из стока в левую долю ребра стоимости и пропускной способности , из правой доли в сток — также ребра стоимости и пропускной способности . Найдем в этой сети максимальный поток минимальной стоимости. Утверждается, что если ребро насыщено потоком, то работа в оптимальном расписании должна стоять на станке в позиции с конца.
- Целевые функции задачи mincost-maxflow и текущей задачи совпадают, так как у ребер между долями пропускная способность 1, а у дополнительных ребер из истока и в сток нулевая стоимость, и они не могут внести вклад в целевую функцию.
- Расписание, построенное по вышепредставленному способу действительно будет допустимым.
- Благодаря ограничениям на поток, входящий в левую долю, каждая работа будет назначена только один раз.
- Благодаря ограничениям на поток, выходящий из правой доли, на каждую позицию будет назначено не более одной работы.
- Докажем, что не возникает ситуации такой, что существует такая позиция , что в этой позиции с конца стоит какая-то работа, а в позиции с конца — нет (это противоречит определению -й с конца работы). Такая ситуация означает, что ребро оказалось насышено потоком, а ребро — не насыщено. Но стоимость ребра меньше стоимости ребра , поэтому можем переместить поток с ребра на ребро , не нарушив свойства потока и улучшив целевую функцию, что противоречит оптимальности ответа для mincost-maxflow. Следовательно, такой позиции не возникнет и расписание будет допустимым.
O | p_ij=1 | Sum(w_i C_i)
Докажем, что оптимальный ответ для равен оптимальному ответу к задаче , где прерывания позволено делать только в целые моменты времени.
- Целевые функции задач совпадают, поэтому из оптимальности следует оптимальность .
- Покажем, как получить из расписания допустимое расписание для (в расписании для допустимость нарушает то, что на одном станке выполняется несколько блоков одной работы):
- Построим двудольный граф, в левую долю которого поместим работы, а в правую — возможные моменты времени. Из вершины, соответствующей работе будет идти ребро в вершину, соответствующую временному моменту , если работа в расписании для претендует на выполнение в момент времени .
- Раскрасим ребра этого графа в цветов, из теории графов известно, что это можно сделать.
- Назначим выполнение единичного элемента работы в момент времени на станке , если соответствующее ребро раскрашено в цвет .
- После данного преобразования мы не изменим значение целевой функции (так как мы переставляем только элементы работ, выполняющихся в один и тот же момент времени). Также расписание станет допустимым для , так как по определению реберной раскраски, не будет ни одной работы, два единичных блока которых выполняется на одном станке и во все моменты времени не окажется того, что на один станок назначено две работы.
Чтобы непосредственно решить эту задачу, воспользуемся теоремой о том, что для задачи существует оптимальное расписание без прерываний[2]. Известно, что для того, чтобы получить оптимальное расписание для такой задачи без прерываний, надо помещать работы по очереди на станки в порядке убывания весов. Длительности у всех работ совпадают, поэтому расписание будет состоять из блоков по работ и, возможно, одного неполного блока из работ. Таким образом, аналогично задаче , чтобы получить допустимое расписание, можно не строить раскраску графа, а просто циклически сдвигать последовательности работ внутри каждого блока, что позволяет достичь асимптотики .
Построение расписания по нижней оценке
Этот метод обычно применим к задачам, в которых целевая функция — . Построим какой-то набор нижних ограничений на произвольное расписание для задачи и возьмем из них максимальное. Затем построим произвольное допустимое расписание, достигающее этой оценки.
С помощью этого метода решаются:
Примеры
P | pmtn | C_max
- В допустимом расписании выполнение всех работ не может завершиться раньше одной из них, поэтому .
- Если все станки работали время , на них могло выполниться не больше работы, то есть и .
- Тогда .
Построим расписание, подходящее под эту границу: будем по очереди заполнять машины работами в произвольном порядке, и если очередная работа не помещается на текущей машине полностью, перенесем ее выходящую за часть на следующую машину. Благодаря первому ограничению никакая работа не будет выполняться одновременно на двух станках, а благодаря второму — не останется работы, которую мы не сможем выполнить.
O | p_ij=1 | C_max
- В допустимом расписании на каждом станке надо обработать каждую работу, поэтому .
- В допустимом расписании каждую работу нужно обработать на всех станках, причем ее нельзя обрабатывать на двух станках одновременно, поэтому .
- Тогда
Оптимальное расписание получается циклическими сдвигами последовательности и выглядит следующим образом:
- Для :
0 1 2 ... n-1 n n+1 ... m-1 m M_1 1 2 3 ... n-1 n - ... - - M_2 - 1 2 ... n-2 n-1 n ... - - . ... ... ... ... ... ... ... ... ... ... M_m-1 - - - ... ... ... ... ... n - M_m - - - ... ... ... ... ... n-1 n
- Для :
0 1 2 ... k k+1 ... n-1 n M_1 1 2 3 ... k k+1 ... n-1 n M_2 n 1 2 ... k-1 k ... n-2 n-1 . ... ... ... ... ... ... ... ... ... . ... ... ... ... ... ... ... ... ... M_m n-m+2 n-m+3 ... ... ... ... ... n-m n-m+1
Бинарный поиск по ответу
Этот способ часто подходит для задач, в которых надо минимизировать . Важно помнить, что если требуется полиномиальное по решение, оно не должно зависеть от логарифма ответа, но иногда ответ ограничен полиномом от (в частности, в ), и мы можем применить этот метод.
Примеры
O | p_ij = 1| Sum(U_i)
Перенумеруем работы по возрастанию их дедлайнов, то есть .
| Утверждение: |
Если мы можем выполнить каких-то работ, мы можем выполнить последних работ. |
| Действительно, если в допустимом расписании все периоды выполнения работы заменить на периоды выполнения работы , оно останется допустимым, так как . |
Таким образом, будем брать последние работ и пытаться составить из них допустимое расписание (для этого известен полиномиальный алгоритм за [3]). Получили решение за .
Жадное построение расписания
| Определение: |
| Жадный алгоритм — алгоритм, в котором локальные оптимизации решения достигают глобального оптимума. |
Естественно, далеко не все оптимизационные задачи можно решать жадно — для этого сначала необходимо доказать оптимальность жадного выбора.
С помощью этого метода решаются:
- (Lawler's algorithm)
- (EDD rule)
Обычно оптимальность жадного выбора доказывают двумя способами:
Неправильно
Приведем пример часто распространенных неправильных действий при доказательстве оптимальности жадного алгоритма:
Пусть предложенным нами алгоритмом мы получили какое-то решение . Атомарными изменениями в этом решении будем получать другие допустимые решения и докажем, что . Тогда решение — оптимально.
Проблема в этих рассуждениях в том, что ими мы доказываем локальную оптимальность алгоритма в решении . Получение же глобального минимума может потребовать нескольких атомарных изменений в расписании, поэтому доказать оптимальность таким образом в общем случае невозможно. Как ближайшую аналогию, можно привести неправильное утверждение для произвольной функции — «если все частные производные неотрицательны, то в точке наблюдается глобальный минимум».
Правильно
Правильная стратегия(агрумент обмена, exchange argument) заключаются в рассмотрении текущего решения и оптимального решения . Далее предлагается способ модификации в так, что:
- , то есть также оптимально.
- «более похоже» на , чем на .
Если такой способ найден, получаем, что какой-то последовательностью модификаций получим , из чего следует оптимальность .
Отношение «более похоже» должно быть отношением частичного строгого порядка. Часто в качестве него можно выбрать отношение «длина наибольшего общего префикса решения и меньше наибольшего общего префикса решения и ». Тогда если мы сможем увеличить длину наибольшего общего префикса для оптимального решения, не нарушив оптимальности, мы приблизимся к . Можно выбирать и более сложные отношения, например, в доказательстве оптимальности алгоритма для решения задачи используется отношение «время последнего прерывания больше или количество прерываний меньше».
Примеры
1 | prec | f_max
Дано множество работ размера , для которых заданы отношения предшествования, нужно минимизировать , где — монотонно неубывают по времени завершения работы .
Приведем алгоритм(Lawler's algorithm) решения за и докажем его оптимальность:
- Пусть — множество еще не назначенных работ. Пусть .
- Назначим работу , у которой нет потомков в и с минимальным значением последней работой в .
| Теорема: |
Предложенный алгоритм оптимален. |
| Доказательство: |
|
Не теряя общности, пронумеруем работы в расписании, построенном нашим алгоритмом, от до . Пусть — оптимальная последовательность работ такая, что наибольший общий суффикс их расписаний — максимален (пусть они впервые различаются в позиции ). Получили, следующую ситуацию: pi: ... ... r-1 k .... j r r+1 ... nДокажем, что можно привести это расписание к оптимальному расписанию с большим общим суффиксом. Заметим, что если выполнить работу r-1 прямо перед r, расписание все еще будет допустимым (несмотря на еще не доказанную оптимальность, наш алгоритм строит только допустимые расписания, а в построенном нами расписании r-1 стояло прямо перед r). По оптимальному расписанию j выполняется непосредственно перед r. Таким образом, у работ j и r нет ни одного потомка в можестве работ 1, 2.. r-2, r-1. По построенной нашим алгоритмом последовательности 1..n мы получаем, что (иначе мы бы поставили последней на тот момент работу j, а не r). Сдвинем в последовательности работы k .. j влево на одну позицию, а работу r-1 поместим перед r. Так как после сдвига влево, не могли увеличиться, максимум так же не мог увеличиться. Следовательно, оптимальная последовательность имела не самый длинный общий суффикс, что противоречит её выбору. |