1precpmtnrifmax — различия между версиями
Sementry (обсуждение | вклад) (→Decompose: +алгоритм) |
Sementry (обсуждение | вклад) (→Decompose: +доказательство) |
||
| Строка 53: | Строка 53: | ||
4 вставить l в промежутки между блоками G, начиная с <tex> r_l </tex> | 4 вставить l в промежутки между блоками G, начиная с <tex> r_l </tex> | ||
5 '''for''' B_j <tex> \in G </tex>: | 5 '''for''' B_j <tex> \in G </tex>: | ||
| − | 6 ans = max(ans, Decompose( | + | 6 ans = max(ans, Decompose(<tex> B_j </tex>)) |
7 return ans | 7 return ans | ||
| + | |||
| + | {{Теорема | ||
| + | |statement= | ||
| + | Расписание, построенное алгоритмом Decompose(), является корректным и оптимальным. | ||
| + | |proof= | ||
| + | Докажем сначала корректность. | ||
| + | |||
| + | Убедимся, что порядок выполнения работ, заданный графом зависимостей, не нарушается. Заметим, что в разбиении <tex> B \setminus l </tex> на блоки существует не более одного блока <tex> B_0 </tex>, расположенного до момента времени <tex> r_l </tex> — иначе после вставки <tex> l </tex> в промежутки между блоками, <tex> B </tex> выполнялся бы с прерываниями. Далее, заметим, что все интервалы времени, на которые назначается работа из блока <tex> B_j </tex>, находятся внутри интервала <tex> [s_j; e_j] </tex>; это относится и к блоку <tex> B_0 </tex>. Из этих двух наблюдений, а также того, что все работы со временами появления меньше, чем <tex> r_l </tex>, будут помещены в блок <tex> B_0 </tex>, следует, что порядок выполнения будет правильным. | ||
| + | |||
| + | Также для корректности требуется, чтобы работы выполнялись не раньше, чем они появляются. Так как время выполнения работы определяется только в строке 4 алгоритма, которая соответствует этому требованию, то условие выполняется. | ||
| + | |||
| + | Найдем теперь нижнюю оценку на <tex> f_{max} </tex>. Пусть <tex> f_{max}(J) </tex> — ответ для множества работ <tex> J </tex>. | ||
| + | |||
| + | Очевидно, для любой работы <tex> j \in J </tex> выполняется <tex> f_{max}(J) \ge f_{max}(J \ j) </tex>, значит, <tex> f_{max}(J) \ge \max\limits_{j \in J} f_{max}(J \ j) </tex>. | ||
| + | |||
| + | Также, так как в оптимальном решении какая-то работа без потомков обязательно заканчивается в блоке <tex> B </tex>, то <tex> f_{max}(J) \ge f_l(e) </tex>. | ||
| + | |||
| + | Отсюда следует <tex> f_{max}(J) \ge \max(f_l(e), \max\limits_{j \in J} f_{max}(J \ j)) </tex>. По псевдокоду алгоритма видно, что его ответ достигает этой нижней оценки. | ||
| + | }} | ||
=== Общий алгоритм === | === Общий алгоритм === | ||
Версия 23:41, 3 июня 2012
Содержание
Постановка задачи
Задача является обобщением , но здесь у работ также есть времена появления, раньше которых их делать запрещено, и их можно прерывать.
Алгоритм
Работу будем обозначать просто ее номером (), при этом, номера работ могут меняться в зависимости от того, по какому параметру они отсортированы. Время появления работы — , время, требуемое для ее выполнения — . Множество ребер графа обозначается как .
Modify
Для начала, модифицируем времена появления работ. Если работа зависит от , то, очевидно, она не может быть начата раньше, чем закончится выполнение </tex> i </tex>, поэтому нужно заменить на . Алгоритм, делающий это, представлен ниже (работы рассматриваются в порядке топологической сортировки):
Modify() 1 for i 2 for j: ij 3
После выполнения этого алгоритма для любых двух работ , таких, что зависит от , выполняется , поэтому, при рассмотрении работ в порядке неубывания времен их появления, они также будут топологически отсортированы.
Blocks
Здесь и далее считается, что работы отсортированы в порядке неубывания модифицированных .
Станок, выполняющий работы, выполняет работу в некоторые интервалы времени и простаивает в остальное время. Следующий алгоритм разбивает множество работ на блоки, внутри которых станок работает без простоя.
Blocks() 1 2 3 for 4 if 5 6 7 8 9 return
Если алгоритм Blocks вызывается от пустого множества, то считаем, что он возвращает также пустое множество.
Определим время начала блока как , а время конца — как .
| Лемма: |
Существует оптимальное расписание, такое, что все во все временные интервалы , соответствующие блокам , построенным алгоритмом Blocks, станок работает без простоя. |
| Доказательство: |
|
Возьмем произвольное оптимальное расписание , в нем деление на блоки может также быть произвольным. Найдем первый такой временной интервал , что в есть период простоя внутри (если таких периодов несколько, будем рассматривать первый из них). Обозначим его за . Возьмем некоторую работу , такую, что она начинается позже, чем в момент времени , не имеет в графе зависимостей предков, завершаемых позже, чем в момент и . Такая работа обязательно существует, иначе для множества работ, выполняемых позже, чем в момент , было бы , и внутри блока был бы простой , что невозможно по построению алгоритма Blocks. Очевидно, мы можем начать выполнять ее в момент времени и полностью, либо частично заполнить простой ; так как — неубывающая функция, то ответ останется оптимальным. Повторяя этот процесс, мы за конечное число шагов придем к оптимальному расписанию с требуемым свойством. |
Decompose
Допустим, у нас есть блок работ, который можно выполнить без прерываний. Общая идея алгоритма Decompose следующая: найдем работу , которую выгоднее всего выполнить последней. Разобъем оставшееся множество работ на блоки, решим задачу для этих блоков рекурсивно и вставим в промежутки между ними, до них и после них, начиная с . Псевдокод этого алгоритма представлен ниже.
Decompose(B) 1 найти 2 ans 3 G Blocks() 4 вставить l в промежутки между блоками G, начиная с 5 for B_j : 6 ans = max(ans, Decompose()) 7 return ans
| Теорема: |
Расписание, построенное алгоритмом Decompose(), является корректным и оптимальным. |
| Доказательство: |
|
Докажем сначала корректность. Убедимся, что порядок выполнения работ, заданный графом зависимостей, не нарушается. Заметим, что в разбиении на блоки существует не более одного блока , расположенного до момента времени — иначе после вставки в промежутки между блоками, выполнялся бы с прерываниями. Далее, заметим, что все интервалы времени, на которые назначается работа из блока , находятся внутри интервала ; это относится и к блоку . Из этих двух наблюдений, а также того, что все работы со временами появления меньше, чем , будут помещены в блок , следует, что порядок выполнения будет правильным. Также для корректности требуется, чтобы работы выполнялись не раньше, чем они появляются. Так как время выполнения работы определяется только в строке 4 алгоритма, которая соответствует этому требованию, то условие выполняется. Найдем теперь нижнюю оценку на . Пусть — ответ для множества работ . Очевидно, для любой работы выполняется , значит, . Также, так как в оптимальном решении какая-то работа без потомков обязательно заканчивается в блоке , то . Отсюда следует . По псевдокоду алгоритма видно, что его ответ достигает этой нижней оценки. |
Общий алгоритм
Выполним Modify(), после чего разобъем все множество работ на блоки и для каждого блока запустим Decompose():
MakeSchedule() 1 Modify() 2 B Blocks() 3 ans 4 for (): 5 ans = max(ans, Decompose()) 6 return ans
Время работы
| Теорема: |
Время работы алгоритма MakeSchedule() — операций. |
| Доказательство: |
|
Обозначим за время, необходимое для выполнения алгоритма MakeSchedule() на n работах. Очевидно, для корректно определенной функции P в силу структуры алгоритма должно выполняться неравенство:
Здесь - размер блока с номером , построенного алгоритмом Blocks(). Заметим, что . Если , то имеем:
Так как , то можно переписать неравенство в следующем виде:
Чтобы получить максимальную нижнюю оценку на , оценим снизу : Так как Значит, при требуемое неравенство будет выполняться. |