1ridipi1 — различия между версиями
Sofya (обсуждение | вклад) (Много правок) |
Sofya (обсуждение | вклад) (Больше изменений) |
||
Строка 13: | Строка 13: | ||
Для начала решим более простую версию исходной задачи, когда все <tex>r_i=1</tex>. | Для начала решим более простую версию исходной задачи, когда все <tex>r_i=1</tex>. | ||
+ | |||
+ | ====Описание алгоритма==== | ||
Будем выполнять работы в порядке возрастания их дедлайна <tex>d_i</tex>. Утверждается, что это оптимальное расписание. | Будем выполнять работы в порядке возрастания их дедлайна <tex>d_i</tex>. Утверждается, что это оптимальное расписание. | ||
Приведем реализацию, на основе которой мы вскоре построим решение основной задачи: | Приведем реализацию, на основе которой мы вскоре построим решение основной задачи: | ||
+ | |||
+ | ====Псевдокод==== | ||
Пусть <tex>S</tex> — множество еще не включенных в расписание задач. Изначально в нем находятся все задачи. | Пусть <tex>S</tex> — множество еще не включенных в расписание задач. Изначально в нем находятся все задачи. | ||
− | '''function''' solve(d: '''int'''[n]): | + | '''function''' solve(d: '''int'''[n]): '''boolean''' |
<tex>S = \{1, 2, \ldots, n\}</tex> | <tex>S = \{1, 2, \ldots, n\}</tex> | ||
− | <tex>time = 1</tex> | + | '''int '''<tex>time = 1</tex> |
− | '''for''' <tex> i = 1 </tex> '''to''' <tex> n </tex> | + | '''for''' <tex> i = 1 </tex> '''to''' <tex> n </tex> |
− | <tex> | + | <tex>d[k] = \min\{d[i] \mid i \in S\}</tex> |
− | '''if''' <tex> | + | '''if''' <tex>d[k] \leqslant time</tex> |
− | + | //расписание составить невозможно | |
+ | '''return false''' | ||
'''else''' | '''else''' | ||
//выполняем работу номер <tex>k</tex> | //выполняем работу номер <tex>k</tex> | ||
− | <tex>S | + | <tex>S = S \setminus \{k\}</tex> |
<tex>time = time + 1</tex> | <tex>time = time + 1</tex> | ||
+ | '''return true''' | ||
Сложность алгоритма <tex>\mathcal{O}(n\log n)</tex>, если в качестве <tex>S</tex> использовать структуру, которая позволяет поиск элемента с минимальным <tex>d_i</tex> и его удаление за <tex>\mathcal{O}(\log n)</tex>, например [[Двоичная_куча|двоичная куча]]. | Сложность алгоритма <tex>\mathcal{O}(n\log n)</tex>, если в качестве <tex>S</tex> использовать структуру, которая позволяет поиск элемента с минимальным <tex>d_i</tex> и его удаление за <tex>\mathcal{O}(\log n)</tex>, например [[Двоичная_куча|двоичная куча]]. | ||
+ | |||
+ | ====Доказательство корректности и оптимальности==== | ||
{{Теорема | {{Теорема | ||
Строка 44: | Строка 52: | ||
Теперь перейдем к решению основной задачи. | Теперь перейдем к решению основной задачи. | ||
+ | |||
+ | ====Описание алгоритма==== | ||
+ | |||
Теперь не все задачи доступны изначально. Однако утверждается, что очередную задачу теперь достаточно выбирать с минимальным <tex>d_{i}</tex> из всех, которые уже доступны. Если эта работа уже просрочена, значит хорошее расписание построить нельзя. | Теперь не все задачи доступны изначально. Однако утверждается, что очередную задачу теперь достаточно выбирать с минимальным <tex>d_{i}</tex> из всех, которые уже доступны. Если эта работа уже просрочена, значит хорошее расписание построить нельзя. | ||
+ | |||
+ | ====Псевдокод==== | ||
Пусть <tex>S</tex> — множество ещё не включенных в расписание работ, к выполнению которых уже можно приступить. Изначально <tex>S</tex> пустое. | Пусть <tex>S</tex> — множество ещё не включенных в расписание работ, к выполнению которых уже можно приступить. Изначально <tex>S</tex> пустое. | ||
Отсортируем работы по порядку их появления. | Отсортируем работы по порядку их появления. | ||
− | + | '''function''' solve(r: '''int'''[n], d: '''int'''[n]): '''boolean''' | |
− | '''function''' solve(r: '''int'''[n], d: '''int'''[n]): | ||
<tex>S = \varnothing</tex> | <tex>S = \varnothing</tex> | ||
− | <tex>j = 1</tex> | + | '''int '''<tex>j = 1</tex> |
− | <tex>time = 1</tex> | + | '''int '''<tex>time = 1</tex> |
− | '''for''' <tex> i = 1 </tex> '''to''' <tex> n </tex> | + | '''for''' <tex> i = 1 </tex> '''to''' <tex> n </tex> |
'''if''' <tex>S == \varnothing</tex> | '''if''' <tex>S == \varnothing</tex> | ||
− | <tex>time= | + | <tex>time=r[j]</tex> |
− | '''while''' <tex>time== | + | '''while''' <tex>time==r[j]</tex> |
− | <tex>S | + | <tex>S = S \cup \{j\}</tex> |
<tex>j = j + 1</tex> | <tex>j = j + 1</tex> | ||
− | <tex> | + | <tex>d[k] = min\{d[i]</tex> | <tex>i \in S\}</tex> |
− | '''if''' <tex> | + | '''if''' <tex>d[k] \leqslant time</tex> |
− | + | //расписание составить невозможно | |
+ | '''return false''' | ||
'''else''' | '''else''' | ||
//выполняем работу номер <tex>k</tex> | //выполняем работу номер <tex>k</tex> | ||
− | <tex>S | + | <tex>S = S \setminus \{k\}</tex> |
<tex>time = time + 1</tex> | <tex>time = time + 1</tex> | ||
+ | '''return true''' | ||
Сложность алгоритма <tex>\mathcal{O}(n\log n)</tex>, если в качестве <tex>S</tex> использовать структуру, которая позволяет поиск элемента с минимальным <tex>d_i</tex> и его удаление за <tex>\mathcal{O}(\log n)</tex>, например [[Двоичная_куча|двоичная куча]]. | Сложность алгоритма <tex>\mathcal{O}(n\log n)</tex>, если в качестве <tex>S</tex> использовать структуру, которая позволяет поиск элемента с минимальным <tex>d_i</tex> и его удаление за <tex>\mathcal{O}(\log n)</tex>, например [[Двоичная_куча|двоичная куча]]. | ||
+ | |||
+ | ====Доказательство корректности и оптимальности==== | ||
{{Теорема | {{Теорема |
Версия 00:15, 5 июня 2016
Задача: |
Дан один станок на котором нужно выполнить | работ. Для каждой работы известны моменты времени, когда можно начинать её выполнять — и когда необходимо закончить её выполнение — . Время выполнения у всех работ одинаково и равно 1. Необходимо узнать, можно ли построить расписание, при котором все работы будут выполнены.
Содержание
Алгоритм
Упрощенная версия
Для начала решим более простую версию исходной задачи, когда все
.Описание алгоритма
Будем выполнять работы в порядке возрастания их дедлайна
. Утверждается, что это оптимальное расписание. Приведем реализацию, на основе которой мы вскоре построим решение основной задачи:Псевдокод
Пусть
— множество еще не включенных в расписание задач. Изначально в нем находятся все задачи.function solve(d: int[n]): booleanint for to if //расписание составить невозможно return false else //выполняем работу номер return true
Сложность алгоритма двоичная куча.
, если в качестве использовать структуру, которая позволяет поиск элемента с минимальным и его удаление за , напримерДоказательство корректности и оптимальности
Теорема: |
Приведенный алгоритм строит оптимальное расписание для задачи . |
Доказательство: |
Докажем от противного. Пусть в оптимальном расписании, где все работы укладываются в дедлайны, сначала идет работа | , а потом , причем . Посмотрим, что произойдет, если в расписании поменять их местами. Так как они обе выполняются за единицу времени, для всех задач, кроме -й и -й время их завершения не поменялось. Для -й же работы стало меньше, что только лучше. увеличилось и стало равно старому однако, раз -я работа раньше укладывалась в дедлайн, то , а значит и -я работа все еще укладывается в свой дедлайн, и наша замена ничего не испортила.
Исходная задача
Теперь перейдем к решению основной задачи.
Описание алгоритма
Теперь не все задачи доступны изначально. Однако утверждается, что очередную задачу теперь достаточно выбирать с минимальным
из всех, которые уже доступны. Если эта работа уже просрочена, значит хорошее расписание построить нельзя.Псевдокод
Пусть
— множество ещё не включенных в расписание работ, к выполнению которых уже можно приступить. Изначально пустое. Отсортируем работы по порядку их появления.function solve(r: int[n], d: int[n]): booleanint int for to if while | if //расписание составить невозможно return false else //выполняем работу номер return true
Сложность алгоритма двоичная куча.
, если в качестве использовать структуру, которая позволяет поиск элемента с минимальным и его удаление за , напримерДоказательство корректности и оптимальности
Теорема: |
Приведенный алгоритм строит оптимальное расписание для задачи . |
Доказательство: |
Пусть с помощью нашего алгоритма составить хорошее расписание не удалось. Докажем, что в этом случае хорошего расписания не существует. Заметим, что расписание состоит из непрерывных блоков, между которыми есть пропуски — все поступившие работы выполнены, а новых работ ещё не появилось. Расписание может состоять из одного блока. Рассмотрим первый блок, для которого не получилось составить расписание. Возьмем в нём первую работу, для которой не нашлось места. Пусть её индекс будет равен . Попробуем вставить эту работу в расписание. До блока её вставить нельзя, так как больше или равно времени начала блока. А в блоке нет пропусков, поэтому нужно поменять её с какой-то -й, которая уже стоит в этом блоке расписания. У всех таких работ , так как в алгоритме мы каждый раз брали работу с минимальным . Но -ю работу нельзя выполнить после -й. Значит -ю работу выполнить нельзя. |
См. также
Источники информации
- P. Brucker. «Scheduling Algorithms» (2006), 5th edition.