1ridipi1 — различия между версиями
Sofya (обсуждение | вклад)  (→Алгоритм)  | 
				м (rollbackEdits.php mass rollback)  | 
				||
| (не показано 9 промежуточных версий 3 участников) | |||
| Строка 1: | Строка 1: | ||
| − | ==  | + | <tex dpi = "200" >1 \mid r_i, d_i, p_i=1 \mid -</tex>  | 
| − | Дан один станок на котором нужно выполнить <tex>n</tex> работ. Для каждой работы известны моменты времени, когда можно начинать её выполнять — <tex>  | + | |
| + | {{Шаблон:Задача  | ||
| + | |definition =    | ||
| + | Дан один станок на котором нужно выполнить <tex>n</tex> работ. Для каждой работы известны моменты времени, когда можно начинать её выполнять — <tex>r_i</tex> и когда необходимо закончить её выполнение — <tex>d_i</tex>. Время выполнения <tex>p_i</tex> у всех работ одинаково и равно 1. Необходимо узнать, можно ли построить расписание, при котором все работы будут выполнены.  | ||
| + | }}  | ||
==Алгоритм==  | ==Алгоритм==  | ||
| − | |||
| − | Пусть <tex>S</tex> - множество ещё не включенных в расписание работ, к выполнению которых уже можно приступить. Изначально <tex>S</tex> пустое.  | + | ===Упрощенная версия===  | 
| + | |||
| + | <tex>1 \mid d_i, p_i=1 \mid -</tex>  | ||
| + | |||
| + | Для начала решим более простую версию исходной задачи, когда все <tex>r_i=1</tex>.  | ||
| + | |||
| + | ====Описание алгоритма====  | ||
| + | |||
| + | Будем выполнять работы в порядке возрастания их дедлайна <tex>d_i</tex>. Утверждается, что это оптимальное расписание.  | ||
| + | Приведем реализацию, на основе которой мы вскоре построим решение основной задачи:  | ||
| + | |||
| + | ====Псевдокод====  | ||
| + | |||
| + | Пусть <tex>S</tex> — множество еще не включенных в расписание задач. Изначально в нем находятся все задачи.  | ||
| + |   '''function''' solve(d: '''int'''[n]): '''boolean'''  | ||
| + |       <tex>S = \{1, 2, \ldots, n\}</tex>  | ||
| + |       '''int '''<tex>time = 1</tex>  | ||
| + |       '''for''' <tex> i = 1 </tex> '''to''' <tex> n </tex>  | ||
| + |           <tex>d[k] = \min\{d[i] \mid i \in S\}</tex>  | ||
| + |           '''if''' <tex>d[k] \leqslant time</tex>  | ||
| + |               <font color=green>// расписание составить невозможно</font>  | ||
| + |               '''return''' ''false''  | ||
| + |           '''else'''  | ||
| + |               <font color=green>// выполняем работу номер k</font>  | ||
| + |               <tex>S = S \setminus \{k\}</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>, например [[Двоичная_куча|двоичная куча]].  | ||
| + | |||
| + | ====Доказательство корректности и оптимальности====  | ||
| + | |||
| + | {{Теорема  | ||
| + | |statement=  | ||
| + | Приведенный алгоритм строит оптимальное расписание для задачи <tex>1 \mid d_i, p_i=1 \mid -</tex>.  | ||
| + | |proof=  | ||
| + | Докажем от противного. Пусть в оптимальном расписании, где все работы укладываются в дедлайны, сначала идет работа <tex>i</tex>, а потом <tex>j</tex>, причем <tex>d_i > d_j</tex>. Посмотрим, что произойдет, если в расписании поменять их местами. Так как они обе выполняются за единицу времени, для всех задач, кроме <tex>i</tex>-й и <tex>j</tex>-й время их завершения <tex>C_i</tex> не поменялось. Для <tex>j</tex>-й же работы <tex>C_j</tex> стало меньше, что только лучше. <tex>C_i</tex> увеличилось и стало равно старому <tex>C_j</tex> однако, раз <tex>j</tex>-я работа раньше укладывалась в дедлайн, то <tex>C_i = C_j^{old} \leqslant d_j < d_i</tex>, а значит и <tex>i</tex>-я работа все еще укладывается в свой дедлайн, и наша замена ничего не испортила.  | ||
| + | }}  | ||
| + | |||
| + | ===Исходная задача===  | ||
| + | |||
| + | <tex>1 \mid r_i, d_i, p_i=1 \mid -</tex>  | ||
| + | |||
| + | Теперь перейдем к решению основной задачи.  | ||
| + | |||
| + | ====Описание алгоритма====  | ||
| + | |||
| + | Теперь не все задачи доступны изначально. Однако утверждается, что очередную задачу теперь достаточно выбирать с минимальным <tex>d_{i}</tex> из всех, которые уже доступны. Если эта работа уже просрочена, значит хорошее расписание построить нельзя.  | ||
| + | |||
| + | ====Псевдокод====  | ||
| + | |||
| + | Пусть <tex>S</tex> — множество ещё не включенных в расписание работ, к выполнению которых уже можно приступить. Изначально <tex>S</tex> пустое.  | ||
Отсортируем работы по порядку их появления.  | Отсортируем работы по порядку их появления.  | ||
| − | + |   '''function''' solve(r: '''int'''[n], d: '''int'''[n]): '''boolean'''  | |
| − | + |       <tex>S = \varnothing</tex>  | |
| − | + |       '''int '''<tex>j = 1</tex>  | |
| − | + |       '''int '''<tex>time = 1</tex>  | |
| − | + |       '''for''' <tex> i = 1 </tex> '''to''' <tex> n </tex>  | |
| − | + |           '''if''' <tex>S == \varnothing</tex>  | |
| − | + |               <tex>time=r[j]</tex>  | |
| − | + |           '''while''' <tex>time==r[j]</tex>  | |
| − | + |               <tex>S = S \cup \{j\}</tex>  | |
| − | + |               <tex>j = j + 1</tex>  | |
| − | + |           <tex>d[k] = \min\{d[i]</tex> | <tex>i \in S\}</tex>  | |
| − | + |           '''if''' <tex>d[k] \leqslant time</tex>  | |
| − | + |               <font color=green>// расписание составить невозможно</font>  | |
| − | + |               '''return''' ''false''  | |
| − | + |           '''else'''  | |
| − | + |               <font color=green>// выполняем работу номер k</font>  | |
| + |               <tex>S = S \setminus \{k\}</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>, например [[Двоичная_куча|двоичная куча]].  | ||
| − | + | ====Доказательство корректности и оптимальности====  | |
| − | ==  | + | {{Теорема  | 
| + | |statement=  | ||
| + | Приведенный алгоритм строит оптимальное расписание для задачи <tex>1 \mid r_i, d_i, p_i=1 \mid -</tex>.  | ||
| + | |proof=  | ||
Пусть с помощью нашего алгоритма составить хорошее расписание не удалось. Докажем, что в этом случае хорошего расписания не существует.  | Пусть с помощью нашего алгоритма составить хорошее расписание не удалось. Докажем, что в этом случае хорошего расписания не существует.  | ||
| − | Заметим, что расписание состоит из непрерывных блоков, между которыми есть пропуски   | + | Заметим, что расписание состоит из непрерывных блоков, между которыми есть пропуски — все поступившие работы выполнены, а новых работ ещё не появилось. Расписание может состоять из одного блока.  | 
| + | |||
| + | Рассмотрим первый блок, для которого не получилось составить расписание. Возьмем в нём первую работу, для которой не нашлось места. Пусть её индекс будет равен <tex>k</tex>. Попробуем вставить эту работу в расписание. До блока её вставить нельзя, так как <tex>r_i</tex> больше или равно времени начала блока. А в блоке нет пропусков, поэтому нужно поменять её с какой-то <tex>i</tex>-й, которая уже стоит в этом блоке расписания. У всех таких работ <tex>d_i \leqslant d_k</tex>, так как в алгоритме мы каждый раз брали работу с минимальным <tex>d_i</tex>. Но <tex>i</tex>-ю работу нельзя выполнить после <tex>k</tex>-й. Значит <tex>k</tex>-ю работу выполнить нельзя.  | ||
| + | }}  | ||
| − | + | == См. также ==  | |
| + | * [[1ripipsumwu|<tex>1 \mid r_i, p_i = p \mid \sum w_i U_i</tex>]]  | ||
| + | * [[1ripi1sumf|<tex>1 \mid r_i, p_i=1 \mid \sum f_i</tex>]]  | ||
==Источники информации==  | ==Источники информации==  | ||
| − | * P. Brucker.   | + | * P. Brucker. «Scheduling Algorithms» (2006), 5th edition.  | 
| − | [[Категория:   | + | [[Категория: Алгоритмы и структуры данных]]  | 
[[Категория: Теория расписаний]]  | [[Категория: Теория расписаний]]  | ||
Текущая версия на 19:21, 4 сентября 2022
| Задача: | 
| Дан один станок на котором нужно выполнить работ. Для каждой работы известны моменты времени, когда можно начинать её выполнять — и когда необходимо закончить её выполнение — . Время выполнения у всех работ одинаково и равно 1. Необходимо узнать, можно ли построить расписание, при котором все работы будут выполнены. | 
Содержание
Алгоритм
Упрощенная версия
Для начала решим более простую версию исходной задачи, когда все .
Описание алгоритма
Будем выполнять работы в порядке возрастания их дедлайна . Утверждается, что это оптимальное расписание. Приведем реализацию, на основе которой мы вскоре построим решение основной задачи:
Псевдокод
Пусть — множество еще не включенных в расписание задач. Изначально в нем находятся все задачи.
 function solve(d: int[n]): boolean
     
     int 
     for  to 
         
         if 
             // расписание составить невозможно
             return false
         else
             // выполняем работу номер k
             
             
     return true 
Сложность алгоритма , если в качестве использовать структуру, которая позволяет поиск элемента с минимальным и его удаление за , например двоичная куча.
Доказательство корректности и оптимальности
| Теорема: | 
Приведенный алгоритм строит оптимальное расписание для задачи .  | 
| Доказательство: | 
| Докажем от противного. Пусть в оптимальном расписании, где все работы укладываются в дедлайны, сначала идет работа , а потом , причем . Посмотрим, что произойдет, если в расписании поменять их местами. Так как они обе выполняются за единицу времени, для всех задач, кроме -й и -й время их завершения не поменялось. Для -й же работы стало меньше, что только лучше. увеличилось и стало равно старому однако, раз -я работа раньше укладывалась в дедлайн, то , а значит и -я работа все еще укладывается в свой дедлайн, и наша замена ничего не испортила. | 
Исходная задача
Теперь перейдем к решению основной задачи.
Описание алгоритма
Теперь не все задачи доступны изначально. Однако утверждается, что очередную задачу теперь достаточно выбирать с минимальным из всех, которые уже доступны. Если эта работа уже просрочена, значит хорошее расписание построить нельзя.
Псевдокод
Пусть — множество ещё не включенных в расписание работ, к выполнению которых уже можно приступить. Изначально пустое. Отсортируем работы по порядку их появления.
 function solve(r: int[n], d: int[n]): boolean
     
     int 
     int 
     for  to 
         if 
             
         while 
             
             
          | 
         if 
             // расписание составить невозможно
             return false
         else
             // выполняем работу номер k
             
             
     return true
Сложность алгоритма , если в качестве использовать структуру, которая позволяет поиск элемента с минимальным и его удаление за , например двоичная куча.
Доказательство корректности и оптимальности
| Теорема: | 
Приведенный алгоритм строит оптимальное расписание для задачи .  | 
| Доказательство: | 
| 
 Пусть с помощью нашего алгоритма составить хорошее расписание не удалось. Докажем, что в этом случае хорошего расписания не существует. Заметим, что расписание состоит из непрерывных блоков, между которыми есть пропуски — все поступившие работы выполнены, а новых работ ещё не появилось. Расписание может состоять из одного блока. Рассмотрим первый блок, для которого не получилось составить расписание. Возьмем в нём первую работу, для которой не нашлось места. Пусть её индекс будет равен . Попробуем вставить эту работу в расписание. До блока её вставить нельзя, так как больше или равно времени начала блока. А в блоке нет пропусков, поэтому нужно поменять её с какой-то -й, которая уже стоит в этом блоке расписания. У всех таких работ , так как в алгоритме мы каждый раз брали работу с минимальным . Но -ю работу нельзя выполнить после -й. Значит -ю работу выполнить нельзя. | 
См. также
Источники информации
- P. Brucker. «Scheduling Algorithms» (2006), 5th edition.