Методы решения задач теории расписаний — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Жадное построение расписания)
м (rollbackEdits.php mass rollback)
 
(не показано 20 промежуточных версий 9 участников)
Строка 1: Строка 1:
 
== Сведение к другой задаче ==
 
== Сведение к другой задаче ==
При сведении текущей задачи теории расписаний <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>, сводятся к задаче на одном станке.
+
* Задачи класса [[Классификация задач|Open Shop]] при условии <tex>p_{ij}=1</tex> можно свести к задачам равной длительности на параллельных станках:
 +
*:[[Opij1Sumwc|<tex> O \mid p_{ij} = 1 \mid \sum w_i C_i </tex>]]
 +
*:<tex> O \mid p_{ij} = 1, r_i \mid C_{max} </tex> <ref>Peter Brucker «Scheduling Algorithms», fifth edition, Springer — с. 161</ref>
 +
* Задачи класса [[Классификация задач|Flow Shop]] при условии <tex>p_{ij}=1</tex> можно свести к задаче на одном станке:
 +
*:[[Fpij1sumwu|<tex> F \mid p_{ij} = 1 \mid \sum w_i U_i </tex>]]
 
* Часто в задачах, в которых допускаются прерывания, оптимальный ответ совпадает с соответствующими задачами без прерываний:
 
* Часто в задачах, в которых допускаются прерывания, оптимальный ответ совпадает с соответствующими задачами без прерываний:
** <tex> P \mid pmtn \mid \sum w_i C_i </tex>
+
*:<tex> P \mid pmtn \mid \sum w_i C_i </tex> <ref>Peter Brucker «Scheduling Algorithms», fifth edition, Springer — с. 121</ref>
** <tex> F2 \mid pmtn \mid C_{max} </tex>
+
*:[[Flow shop|<tex> F2 \mid pmtn \mid C_{max} </tex>]]
 
+
* Ряд задач можно свести к задаче поиска максимального потока:
=== Примеры ===
+
*:<tex> Q \mid pmtn, r_i\mid L_{max} </tex> <ref>Peter Brucker «Scheduling Algorithms», fifth edition, Springer — с. 129-133</ref>
==== 1 | intree | Sum(w_i C_i) ====
+
*:[[RSumCi|<tex> R \mid \mid \sum C_i </tex>]]
Предположим, что мы уже умеем решать задачу <tex> S' = 1 \mid outtree \mid \sum w_i C_i </tex><ref>P. Brucker. Scheduling Algorithms (2006), 5th edition, p. 73 </ref>. Сведем нашу задачу <tex> S </tex> к ней следующим образом:
+
* Некоторые задачи сводятся к другим похожим задачам теории расписаний путем преобразования их расписаний:
* Развернем все ребра, теперь если работа <tex> i </tex> зависела от работы <tex> j </tex>, работа <tex> j </tex> будет зависеть от <tex> i </tex>.
+
*:[[1outtreesumwc|<tex> 1 \mid intree \mid \sum w_i C_i </tex>]]
* Заменим все стоимости <tex> w_i </tex> на противоположные <tex> w'_i = - w_i</tex>.
 
Утверждается, что решив соответствующую задачу <tex> S' </tex> и развернув полученное расписание, мы получим ответ для текущей задачи.
 
# Полученное расписание будет допустимым, так как расписание для <tex> S' </tex> было допустимым, и в нем никакие две работы не пересекались и не прерывались. Развернув, мы не могли нарушить это свойство. Также из-за того, что мы развернули расписание, мы добились того, что все работы выполняются в правильном порядке (в расписании для <tex> S' </tex> из-за того, что все ребра были развернуты, порядок был нарушен для всех работ). Таким образом, получили что расписание — допустимое.
 
# Пусть с помощью задачи <tex> S' </tex> мы получили последовательность работ <tex> 1 \dots n </tex>. Распишем по определению значение целевой функции для <tex> S' </tex>:
 
#: <tex>\sum -w_i C_i = \sum \limits_{i=1}^n ( -w_i \sum \limits_{j=1}^i p_j ) = \\
 
\sum\limits_{i=1}^n ( w_i \sum\limits_{j=i+1}^n p_j ) - \sum\limits_{i=1}^n w_i \sum \limits_{i=1}^n p_i = \\
 
\sum\limits_{i=1}^n ( w_i \sum\limits_{j=i}^n p_j ) - \sum\limits_{i=1}^n w_i p_i - \sum\limits_{i=1}^n w_i \sum \limits_{i=1}^n p_i </tex>
 
#: Заметим, что первое слагаемое соответствует целевой функции <tex> \sum w_i C_i </tex> для последовательности <tex> n \dots 1 </tex>, а второе и третье слагаемые — константы, зависящие только от входных данных и не зависящие от перестановки работ. Таким образом, оптимальное значение для <tex> S' </tex> также минимизирует <tex> S </tex>, ч.т.д.
 
 
 
==== R || Sum(C_i) ====
 
В этой задаче дано <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> k </tex>, означающий, что соответствующая работа выпллняется <tex> k </tex>-й с конца. Понятно, что в различных расписаниях <tex> k </tex> может принимать значения от <tex>1</tex> до <tex>n</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, а у дополнительных ребер из истока и в сток нулевая стоимость, и они не могут внести вклад в целевую функцию.
 
# Расписание, построенное по вышепредставленному способу действительно будет допустимым.
 
## Благодаря ограничениям на поток, входящий в левую долю, каждая работа будет назначена только один раз.
 
## Благодаря ограничениям на поток, выходящий из правой доли, на каждую позицию будет назначено не более одной работы.
 
## Докажем, что не возникает ситуации такой, что существует такая позиция <tex> l </tex>, что в этой позиции с конца стоит какая-то работа, а в позиции <tex> l - 1 </tex> с конца — нет (это противоречит определению <tex>l</tex>-й с конца работы). Такая ситуация означает, что ребро <tex> i \to (j, l) </tex> оказалось насышено потоком, а ребро <tex>i \to (j, l - 1) </tex> — не насыщено. Но стоимость ребра <tex> i \to (j, l - 1) </tex> меньше стоимости ребра <tex> i \to (j, l) </tex>, поэтому можем переместить поток с ребра <tex> i \to (j, l) </tex> на ребро <tex> i \to (j, l - 1) </tex>, не нарушив свойства потока и улучшив целевую функцию, что противоречит оптимальности ответа для mincost-maxflow. Следовательно, такой позиции не возникнет и расписание будет допустимым.
 
 
 
==== O | p_ij=1 | Sum(w_i C_i) ====
 
Докажем, что оптимальный ответ для <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> i </tex> будет идти ребро в вершину, соответствующую временному моменту <tex> t</tex>, если работа <tex> i </tex> в расписании для <tex> S' </tex> претендует на выполнение в момент времени <tex>t</tex>.
 
## Раскрасим ребра этого графа в <tex>m</tex> цветов, из теории графов известно, что это можно сделать.
 
## Назначим выполнение единичного элемента работы <tex>i</tex> в момент времени <tex>t</tex> на станке <tex>k</tex>, если соответствующее ребро раскрашено в цвет <tex>k</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>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>.
 
  
 
== Построение расписания по нижней оценке ==
 
== Построение расписания по нижней оценке ==
Этот метод обычно применим к задачам, в которых целевая функция — <tex> C_{max}</tex>. Построим какой-то набор нижних ограничений на произвольное расписание для задачи <tex> S </tex> и возьмем из них максимальное. Затем построим произвольное допустимое расписание, достигающее этой оценки.
+
Этот метод обычно применим к задачам, в которых целевая функция — <tex> C_{max}</tex>.  
 +
Обычно построение расписания по нижней оценке происходит в два этапа:
 +
# Построение некоторого набора нижних ограничений на произвольное расписание для задачи <tex> S </tex>.  
 +
# Построение произвольного допустимого расписания, достигающего максимального ограничения из построенного набора.
  
С помощью этого метода решаются:
+
С помощью этого метода решаются следующие задачи:
* <tex> P \mid pmtn \mid C_{max}</tex>
+
* <tex> P \mid pmtn \mid C_{max}</tex> <ref>Peter Brucker «Scheduling Algorithms», fifth edition, Springer — с. 108</ref>
* <tex> R \mid pmtn \mid C_{max}</tex>
+
* [[RpmtnCmax|<tex> R \mid pmtn \mid C_{max}</tex>]]
* <tex> O \mid p_{ij}=1 \mid C_{max}</tex>
+
* [[Opij1Cmax|<tex> O \mid p_{ij}=1 \mid C_{max}</tex>]]
 +
* [[QpmtnCmax|<tex> Q \mid pmtn \mid C_{max}</tex>]]
  
=== Примеры ===
+
Ниже будет рассмотрен частный пример решения задачи подобным образом:
==== P | pmtn | C_max ====
+
=== P | pmtn | C_max ===
# В допустимом расписании выполнение всех работ не может завершиться раньше одной из них, поэтому <tex> T \ge p_i </tex>.
+
{{Задача
# Если все станки работали время <tex> T </tex>, на них могло выполниться не больше <tex> Tm </tex> работы, то есть <tex> \sum\limits_i p_i \le Tm </tex> и <tex> T \ge \frac1m \sum\limits_i p_i </tex>.
+
|definition = Имеется <tex>m</tex> однородных машин, работающих параллельно, и <tex>n</tex> работ, которые могут быть прерваны и продолжены позже. Необходимо минимизировать время выполнения всех работ
# Тогда <tex> T_{min} = \max {(\max\limits_i p_i, \frac1m \sum\limits_i p_i)} </tex>.
+
}}
Построим расписание, подходящее под эту границу: будем по очереди заполнять машины работами в произвольном порядке, и если очередная работа не помещается на текущей машине полностью, перенесем ее выходящую за <tex> T_{min} </tex> часть на следующую машину. Благодаря первому ограничению никакая работа не будет выполняться одновременно на двух станках, а благодаря второму — не останется работы, которую мы не сможем выполнить.
+
Найдем набор ограничений на значение <tex> C_{max} </tex> для произвольного допустимого расписания <tex> S </tex> :
 +
# В допустимом расписании выполнение всех работ не может завершиться раньше одной из них, поэтому <tex> C_{max} \geqslant p_i </tex>.
 +
# Если все станки работали время <tex> C_{max} </tex>, на них могло выполниться не больше <tex> C_{max} \cdot m </tex> работы, то есть <tex> \sum\limits_{i=1}^n p_i \leqslant C_{max} \cdot m </tex> и <tex> C_{max} \geqslant \dfrac1m \sum\limits_{i=1}^n p_i </tex>.
 +
Из этих ограничений следует, что <tex> C_{max} = \max {\left( \max\limits_{i=1 \cdots  n} p_i,~ \dfrac1m \sum\limits_{i=1}^n p_i \right)} </tex>.
  
==== O | p_ij=1 | C_max ====
+
Построим расписание, подходящее под эту границу: будем по очереди заполнять машины работами в произвольном порядке, и если очередная работа не помещается на текущей машине полностью, перенесем ее выходящую за <tex> C_{max} </tex> часть на следующую машину. Благодаря первому ограничению никакая работа не будет выполняться одновременно на двух станках, а благодаря второму — не останется работы, которую мы не сможем выполнить.
# В допустимом расписании на каждом станке надо обработать каждую работу, поэтому <tex> T \ge n </tex>.
 
# В допустимом расписании каждую работу нужно обработать на всех станках, причем ее нельзя обрабатывать на двух станках одновременно, поэтому <tex> T \ge m </tex>.
 
# Тогда <tex> T_{min} = \max {(m, n)} </tex>
 
Оптимальное расписание получается циклическими сдвигами последовательности <tex> 1 \dots n </tex> и выглядит следующим образом:
 
* Для <tex> n < m </tex>:
 
        '''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
 
* Для <tex> n \ge m </tex>:
 
        '''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
 
  
 
== Бинарный поиск по ответу ==
 
== Бинарный поиск по ответу ==
 
Этот способ часто подходит для задач, в которых надо минимизировать <tex>C_{max} </tex> (если мы умеем решать соответствующую задачу существования расписания), реже для <tex> \sum w_i U_i </tex>. Важно помнить, что если требуется полиномиальное по <tex> n </tex> решение, оно не должно зависеть от логарифма ответа, но иногда ответ ограничен полиномом от <tex>n</tex>, и мы можем применить этот метод.
 
Этот способ часто подходит для задач, в которых надо минимизировать <tex>C_{max} </tex> (если мы умеем решать соответствующую задачу существования расписания), реже для <tex> \sum w_i U_i </tex>. Важно помнить, что если требуется полиномиальное по <tex> n </tex> решение, оно не должно зависеть от логарифма ответа, но иногда ответ ограничен полиномом от <tex>n</tex>, и мы можем применить этот метод.
=== Примеры ===
+
 
==== O | p_ij = 1| Sum(U_i) ====
+
Примером решения задач подобным методом служит следующая задача:
Перенумеруем работы по неубыванию их дедлайнов, то есть <tex> d_1 \le d_2 \le \dots d_n </tex>.
+
[[QpmtnriLmax|<tex> Q \mid pmtn, r_i \mid L_{max} </tex>]]
{{Утверждение
 
|statement=
 
Если мы можем выполнить <tex> k </tex> каких-то работ, мы можем выполнить <tex> k </tex> последних работ.
 
|proof=
 
Действительно, если в допустимом расписании все периоды выполнения <tex> t_{iq} </tex> работы <tex> i </tex> заменить на периоды выполнения работы <tex> j > i </tex>, оно останется допустимым, так как <tex> t_{iq} \le d_i \le d_j </tex>.
 
}}
 
Таким образом, будем брать последние <tex> k </tex> работ и пытаться составить из них допустимое расписание (для этого известен полиномиальный алгоритм за <tex> O(mn) </tex><ref>P. Brucker. Scheduling Algorithms (2006), 5th edition, p. 163 </ref>). Получили решение за <tex> O(mn\log n ) </tex>.
 
  
 
== Жадное построение расписания ==
 
== Жадное построение расписания ==
{{Определение
+
Для решения задач теории расписаний часто применяется [[Определение матроида|теория матроидо]]в, а в частности — [[Теорема Радо-Эдмондса (жадный алгоритм)|жадный алгоритм]]: алгоритм решения задач путем выбора локально оптимальных решений на каждом этапе алгоритма.
|definition=
 
'''Жадный алгоритм''' — алгоритм, в котором локальные оптимизации решения достигают глобального оптимума.
 
}}
 
 
 
 
Естественно, далеко не все оптимизационные задачи можно решать жадно — для этого сначала необходимо доказать оптимальность жадного выбора.  
 
Естественно, далеко не все оптимизационные задачи можно решать жадно — для этого сначала необходимо доказать оптимальность жадного выбора.  
  
 
С помощью этого метода решаются:
 
С помощью этого метода решаются:
* <tex> 1 \mid prec \mid f_{max} </tex> (''Lawler's algorithm)
+
* [[Правило Лаулера|<tex> 1 \mid prec \mid f_{max} </tex>]]
* <tex> 1 \mid outtree \mid \sum w_i C_i </tex>
+
* [[1outtreesumwc|<tex> 1 \mid outtree \mid \sum w_i C_i </tex>]]
* <tex> 1 \mid p_i = 1 \mid \sum w_i U_i </tex> (''Earliest Due Date rule'')
+
* [[1pi1sumwu|<tex> 1 \mid p_i = 1 \mid \sum w_i U_i </tex>]]
* <tex> 1 \mid \mid \sum U_i </tex>
+
* [[1sumu|<tex> 1 \mid \mid \sum U_i </tex>]]
  
 
Обычно оптимальность жадного выбора доказывают двумя способами:  
 
Обычно оптимальность жадного выбора доказывают двумя способами:  
Строка 118: Строка 65:
 
Приведем пример часто распространенных '''неправильных''' действий при доказательстве оптимальности жадного алгоритма:
 
Приведем пример часто распространенных '''неправильных''' действий при доказательстве оптимальности жадного алгоритма:
  
Пусть предложенным нами алгоритмом мы получили какое-то решение <tex> S </tex>. Атомарными изменениями в этом решении <tex> S </tex> будем получать другие допустимые решения <tex> S' </tex> и докажем, что <tex> f(S) \le f(S') </tex>. Тогда решение <tex> S </tex> — оптимально.
+
Пусть предложенным нами алгоритмом мы получили какое-то решение <tex> S </tex>. Атомарными изменениями в этом решении <tex> S </tex> будем получать другие допустимые решения <tex> S' </tex> и докажем, что <tex> f(S) \leqslant f(S') </tex>. Тогда решение <tex> S </tex> — оптимально.
  
Проблема в этих рассуждениях в том, что ими мы доказываем локальную оптимальность алгоритма в решении <tex> S </tex>. Получение же глобального минимума может потребовать нескольких атомарных изменений в расписании, поэтому доказать оптимальность таким образом в общем случае невозможно. Как ближайшую аналогию, можно привести '''неправильное''' утверждение для произвольной функции <tex> f(\bar x) </tex> — «если все частные производные <tex> \frac{\partial f}{\partial x_1} \dots \frac{\partial f}{\partial x_n} </tex> неотрицательны, то в точке <tex> \bar x </tex> наблюдается глобальный минимум».
+
Проблема в этих рассуждениях в том, что ими мы доказываем локальную оптимальность алгоритма в решении <tex> S </tex>. Получение же глобального минимума может потребовать нескольких атомарных изменений в расписании, поэтому доказать оптимальность таким образом в общем случае невозможно. Как ближайшую аналогию, можно привести '''неправильное''' утверждение для произвольной функции <tex> f(\bar x) </tex> — «если все частные производные <tex> \dfrac{\partial f}{\partial x_1} \dots \dfrac{\partial f}{\partial x_n} </tex> неотрицательны, то в точке <tex> \bar x </tex> наблюдается глобальный минимум».
  
 
=== Правильно ===
 
=== Правильно ===
Правильная стратегия(агрумент обмена, ''exchange argument'') заключаются в рассмотрении текущего решения <tex> S </tex> и оптимального решения <tex> O </tex>. Далее предлагается способ модификации <tex> O </tex> в <tex> O'</tex> так, что:
+
При доказательстве оптимательности применима стратегия '''аргумент замены''' (англ. ''exchange argument''). Стратегия заключается в рассмотрении текущего решения <tex> S </tex> и оптимального решения <tex> O </tex>. Далее предлагается способ модификации <tex> O </tex> в <tex> O'</tex> так, что:
# <tex> f(O') \le f(O) </tex>, то есть <tex> O' </tex> также оптимально.
+
# <tex> f(O') \leqslant f(O) </tex>, то есть <tex> O' </tex> также оптимально.
 
# <tex> O' </tex> «более похоже» на <tex> S </tex>, чем на <tex> O </tex>.
 
# <tex> O' </tex> «более похоже» на <tex> S </tex>, чем на <tex> O </tex>.
  
Если такой способ найден, получаем, что какой-то последовательностью модификаций <tex> O \to O_t' \to \dots \to O_1' \to S </tex> получим <tex> f(S) \le f(O_1') \le \dots \le f(O_t') \le f(O) </tex>, из чего следует оптимальность <tex> S </tex>.
+
Если такой способ найден, получаем, что какой-то последовательностью модификаций <tex> O \to O_t' \to \dots \to O_1' \to S </tex> получим <tex> f(S) \leqslant f(O_1') \leqslant \dots \leqslant f(O_t') \leqslant f(O) </tex>, из чего следует оптимальность <tex> S </tex>.
 
 
Отношение «более похоже» должно быть [[Отношение порядка | отношением частичного строгого порядка]]. Часто в качестве него можно выбрать отношение «длина наибольшего общего префикса решения <tex> A </tex> и <tex> S </tex> меньше наибольшего общего префикса решения <tex> B </tex> и <tex> S </tex>». Тогда если мы сможем увеличить длину наибольшего общего префикса для оптимального решения, не нарушив оптимальности, мы приблизимся к <tex> S </tex>. Можно выбирать и более сложные отношения, например, в доказательстве оптимальности алгоритма <tex> P \mid \mid \sum w_i C_i </tex> для решения задачи <tex> P \mid pmtn \mid \sum w_i C_i </tex> используется отношение «время последнего прерывания больше или количество прерываний меньше». 
 
 
 
=== Примеры ===
 
==== 1 | prec | f_max ====
 
Дано множество работ <tex> J </tex> размера <tex> n </tex>, для которых заданы отношения предшествования, нужно минимизировать <tex> f_{max} = \max\limits_i f_i(C_i) </tex>, где <tex> f_i</tex> — монотонно неубывают по времени завершения работы <tex> i </tex>.
 
 
 
Приведем алгоритм(''Lawler's algorithm'') решения за <tex> O(n^2) </tex> и докажем его оптимальность:
 
# Пусть <tex> U \subseteq J </tex> — множество еще не назначенных работ. Пусть <tex> p(U) = \sum\limits_{i \in U} p_i </tex>.
 
# Назначим работу <tex> j \in U </tex>, у которой нет потомков в <tex> U </tex> и с минимальным значением <tex> f_j(p(U)) </tex> последней работой в <tex> U </tex>.
 
 
 
{{Теорема
 
|statement=
 
Предложенный алгоритм оптимален.
 
|proof=
 
Не теряя общности, пронумеруем работы в расписании, построенном нашим алгоритмом, от <tex> 1 </tex> до <tex> n </tex>. Пусть <tex> \pi(1) \dots \pi(n) </tex> — оптимальная последовательность работ такая, что наибольший общий суффикс их расписаний — максимален (пусть они впервые различаются в позиции <tex> r </tex>). Получили, следующую ситуацию:
 
  
pi: ... ... r-1 k .... j r r+1 ... n
+
Отношение «более похоже» должно быть [[Отношение порядка | отношением частичного строгого порядка]]. Часто в качестве него можно выбрать отношение «длина наибольшего общего префикса решения <tex> A </tex> и <tex> S </tex> меньше наибольшего общего префикса решения <tex> B </tex> и <tex> S </tex>». Тогда если мы сможем увеличить длину наибольшего общего префикса для оптимального решения, не нарушив оптимальности, мы приблизимся к <tex> S </tex>. Можно выбирать и более сложные отношения, например, в доказательстве оптимальности алгоритма <tex> P \mid \mid \sum w_i C_i </tex> для решения задачи <tex> P \mid pmtn \mid \sum w_i C_i </tex> используется отношение «время последнего прерывания больше или количество прерываний меньше».
  
Докажем, что можно привести это расписание к оптимальному расписанию с большим общим суффиксом. Заметим, что если выполнить работу r-1 прямо перед r, расписание все еще будет допустимым (несмотря на еще не доказанную оптимальность, наш алгоритм строит только допустимые расписания, а  в построенном нами расписании r-1 стояло прямо перед r). По оптимальному расписанию j выполняется непосредственно перед r. Таким образом, у работ j и r нет ни одного потомка в можестве работ 1, 2.. r-2, r-1. По построенной нашим алгоритмом последовательности 1..n мы получаем, что <tex> f_{r-1}(\sum\limits_{i}^{r-1} p_i) \le f_j(\sum\limits_{i}^{r-1}) </tex> (иначе мы бы поставили последней на тот момент работу j, а не r). Сдвинем в последовательности <tex> \pi </tex> работы k .. j влево на одну позицию, а работу r-1 поместим перед r. Так как после сдвига влево, <tex>f_k \dots f_j </tex> не могли увеличиться, максимум так же не мог увеличиться. Следовательно, оптимальная последовательность <tex> \pi </tex> имела не самый длинный общий суффикс, что противоречит её выбору.
+
== См. также. ==
}}
+
* [[Правило Лаулера]]
 +
* [[Flow shop]]
 +
* [[Opi1sumu|<tex> O \mid p_{ij} = 1 \mid \sum U_i</tex>]]
  
 
== Примечания ==
 
== Примечания ==
 
<references/>
 
<references/>
  
[[Категория: Дискретная математика и алгоритмы]]
+
==  Источники информации ==
 +
* Peter Brucker «Scheduling Algorithms», fifth edition, Springer ISBN 978-3-540-69515-8
 +
 
 +
[[Категория: Алгоритмы и структуры данных]]
 
[[Категория: Теория расписаний]]
 
[[Категория: Теория расписаний]]

Текущая версия на 19:31, 4 сентября 2022

Сведение к другой задаче

При сведении текущей задачи теории расписаний S к какой-то другой S (не обязательно задаче теории расписаний) необходимо доказать два пункта:

  1. Допустимость расписания, построенного с помощью задачи S, или существование способа его трансформации в допустимое без нарушения оптимальности.
  2. Следствие того, что если мы оптимизируем S, мы также оптимизируем ответ для S.

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

С помощью этого метода решаются:

Построение расписания по нижней оценке

Этот метод обычно применим к задачам, в которых целевая функция — Cmax. Обычно построение расписания по нижней оценке происходит в два этапа:

  1. Построение некоторого набора нижних ограничений на произвольное расписание для задачи S.
  2. Построение произвольного допустимого расписания, достигающего максимального ограничения из построенного набора.

С помощью этого метода решаются следующие задачи:

Ниже будет рассмотрен частный пример решения задачи подобным образом:

P | pmtn | C_max

Задача:
Имеется m однородных машин, работающих параллельно, и n работ, которые могут быть прерваны и продолжены позже. Необходимо минимизировать время выполнения всех работ

Найдем набор ограничений на значение Cmax для произвольного допустимого расписания S :

  1. В допустимом расписании выполнение всех работ не может завершиться раньше одной из них, поэтому Cmaxpi.
  2. Если все станки работали время Cmax, на них могло выполниться не больше Cmaxm работы, то есть ni=1piCmaxm и Cmax1mni=1pi.

Из этих ограничений следует, что Cmax=max(maxi=1npi, 1mni=1pi).

Построим расписание, подходящее под эту границу: будем по очереди заполнять машины работами в произвольном порядке, и если очередная работа не помещается на текущей машине полностью, перенесем ее выходящую за Cmax часть на следующую машину. Благодаря первому ограничению никакая работа не будет выполняться одновременно на двух станках, а благодаря второму — не останется работы, которую мы не сможем выполнить.

Бинарный поиск по ответу

Этот способ часто подходит для задач, в которых надо минимизировать Cmax (если мы умеем решать соответствующую задачу существования расписания), реже для wiUi. Важно помнить, что если требуется полиномиальное по n решение, оно не должно зависеть от логарифма ответа, но иногда ответ ограничен полиномом от n, и мы можем применить этот метод.

Примером решения задач подобным методом служит следующая задача: Qpmtn,riLmax

Жадное построение расписания

Для решения задач теории расписаний часто применяется теория матроидов, а в частности — жадный алгоритм: алгоритм решения задач путем выбора локально оптимальных решений на каждом этапе алгоритма. Естественно, далеко не все оптимизационные задачи можно решать жадно — для этого сначала необходимо доказать оптимальность жадного выбора.

С помощью этого метода решаются:

Обычно оптимальность жадного выбора доказывают двумя способами:

Неправильно

Приведем пример часто распространенных неправильных действий при доказательстве оптимальности жадного алгоритма:

Пусть предложенным нами алгоритмом мы получили какое-то решение S. Атомарными изменениями в этом решении S будем получать другие допустимые решения S и докажем, что f(S)f(S). Тогда решение S — оптимально.

Проблема в этих рассуждениях в том, что ими мы доказываем локальную оптимальность алгоритма в решении S. Получение же глобального минимума может потребовать нескольких атомарных изменений в расписании, поэтому доказать оптимальность таким образом в общем случае невозможно. Как ближайшую аналогию, можно привести неправильное утверждение для произвольной функции f(ˉx) — «если все частные производные fx1fxn неотрицательны, то в точке ˉx наблюдается глобальный минимум».

Правильно

При доказательстве оптимательности применима стратегия аргумент замены (англ. exchange argument). Стратегия заключается в рассмотрении текущего решения S и оптимального решения O. Далее предлагается способ модификации O в O так, что:

  1. f(O)f(O), то есть O также оптимально.
  2. O «более похоже» на S, чем на O.

Если такой способ найден, получаем, что какой-то последовательностью модификаций OOtO1S получим f(S)f(O1)f(Ot)f(O), из чего следует оптимальность S.

Отношение «более похоже» должно быть отношением частичного строгого порядка. Часто в качестве него можно выбрать отношение «длина наибольшего общего префикса решения A и S меньше наибольшего общего префикса решения B и S». Тогда если мы сможем увеличить длину наибольшего общего префикса для оптимального решения, не нарушив оптимальности, мы приблизимся к S. Можно выбирать и более сложные отношения, например, в доказательстве оптимальности алгоритма P∣∣wiCi для решения задачи PpmtnwiCi используется отношение «время последнего прерывания больше или количество прерываний меньше».

См. также.

Примечания

  1. Перейти Peter Brucker «Scheduling Algorithms», fifth edition, Springer — с. 161
  2. Перейти Peter Brucker «Scheduling Algorithms», fifth edition, Springer — с. 121
  3. Перейти Peter Brucker «Scheduling Algorithms», fifth edition, Springer — с. 129-133
  4. Перейти Peter Brucker «Scheduling Algorithms», fifth edition, Springer — с. 108

Источники информации

  • Peter Brucker «Scheduling Algorithms», fifth edition, Springer ISBN 978-3-540-69515-8