Ppi1riintegerLmax

Материал из Викиконспекты
Перейти к: навигация, поиск

Ppi=1;riintegerLmax

Задача:
Дано m однородных станков, работающих параллельно, и n работ с временем выполнения pi=1, временем появления ri, заданным целым числом, и моментом времени di, к которому нужно выполнить работу. Необходимо построить такое расписание, чтобы значение максимального опоздания Lmax=maxi=1n(Cidi) было минимальным.

Описание алгоритма

Идея

Отсортируем все работы по времени появления в неубывающем порядке так, что r1r2rn. Теперь будем выполнять доступные на данный момент работы в порядке неубывания дедлайнов di. То есть, если в момент времени t есть свободные станки и есть невыполненные работы такие, что rit, то назначаем работу с наименьшим дедлайном di на свободный станок.

Псевдокод

Алгоритм принимает на вход массив пар, где первый элемент является временем появления ri работы, а второй её дедлайном di, и возвращает расписание, представленное массивом, где на позиции i стоит момент обработки работы i.

function scheduling(jobs: <int, int>[n]) -> int[n]
    sort(jobs) // сортируем работы в порядке неубывания времени появления
    int j = 1 // последняя невыполненная работа
    int[n] ans // массив, куда будет записано расписание
    Heap<int> M // куча, в которой будем хранить доступные на данный момент работы в порядке неубывания дедлайнов
    while j <= n
        int time = jobs[j].first // время начала выполнения текущего блока работ
        while jobs[j].first <= time // добавляем в кучу все невыполненные работы, доступные на данный момент
           M.push(j)
           j++
        
        int k = 0 // количество занятых станков в данный момент времени
        while M.notEmpty
           i = M.pop() // получаем доступную работу с наименьшим дедлайном 
           ans[i] = t // назначаем работу i на время t
           if k + 1 < m // если в момент t есть свободный станок, то назначаем работу i на него
               k++
           else // иначе увеличиваем время и обновляем список доступных работ
               t++
               k = 0
               while jobs[j].first <= time
                   M.push(j)
                   j++
Пример работы алгоритма при вещественных ri

Внутренний цикл while распределяет работы блоками, в которых они выполняются без простоя станков. После окончания такого блока, время начала выполнения следующего будет равно текущему значению rj.

Асимптотика

Сначала мы сортируем работы, что занимает O(nlogn). Далее идёт цикл, в котором мы n раз кладём элемент в кучу и n раз извлекаем, что также занимает O(nlogn) времени. В итоге всё вместе составляет асимптотику алгоритма O(nlogn).

Замечание

Стоит отметить тот факт, что если снять ограничение на целочисленность ri и позволить им принимать вещественные значения, то представленный алгоритм перестанет строить оптимальное расписание, как видно из контрпримера.

Доказательство корректности алгоритма

Теорема:
Приведенный алгоритм строит оптимальное расписание для задачи Ppi=1;riintegerLmax.
Доказательство:

Пусть S — расписание построенное предложенным алгоритмом, а S оптимальное расписание со следующими свойствами:

  • первые r1 работ из S в обоих расписаниях назначены на одно и тоже время и
  • значение r1 — наибольшее.
Таким образом работа Jr в расписании S назначена на время t, а в расписании S на другой более поздний момент времени. Если в момент времени t в расписании S есть свободный станок, то работа Jr может быть назначена на этот станок и выполнена в момент t. Иначе существует работа Jk такая, что drdk, которая выполнится в расписании S в момент t, а в S в другое время. Тогда мы меняем местами работы Jk и Jr в расписании S, что не нарушает оптимальность S, но является противоречием максимальности значения r1.

См. также

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

  • Peter Brucker «Scheduling Algorithms», fifth edition, Springer — с. 111-112 ISBN 978-3-540-69515-8