1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7

# теория · шаг 2 из 7

Доказательство обменом: как проверить жадный шаг

Коротко

Обменный аргумент - главный инструмент доказательства жадных алгоритмов. Схема одна и та же: возьми ЛЮБОЙ оптимальный ответ, найди в нём место, где он расходится с жадным, и покажи, что замена его элемента на наш НЕ УХУДШАЕТ ответ. Тогда существует оптимум, содержащий жадный выбор, - шаг безопасен, и дальше работает индукция. Второй способ, обычно проще в счётных задачах: жадный не отстаёт - доказать, что после каждого шага жадный ответ не хуже любого другого по выбранной мере. Оба доказательства короткие - пять-шесть строк, - и оба обязательны: без них жадный алгоритм остаётся догадкой.

Если ты умеешь провести обменный аргумент сам и знаешь, чем он отличается от «жадный не отстаёт», листай до «Теперь сам».

Как думаешь, что доказывать

Соблазнительно доказывать так: «наш первый выбор - самый выгодный, значит ответ оптимален». Но это неверно даже по форме. На выборе занятий жадность берёт то, что заканчивается раньше всех, - и это занятие может быть вообще никаким: короткое, в неудобное время, в единственном оптимальном расписании его может не быть.

Значит доказывать надо не «наш выбор лучший». А что тогда? Подумай, какая формулировка была бы достаточна для индукции - и при этом выполнимой.

На что это похоже

Обмен в сборной. Тренер объявил состав - это «оптимальный ответ». Ты хочешь доказать, что твой игрок достоин места. Доказывать «он сильнее всех» бессмысленно: это и неправда, и не нужно. Нужно другое: показать, что если заменить ОДНОГО игрока состава на твоего, сборная играть хуже не станет. Тогда существует состав той же силы, в котором твой игрок есть, - и спорить больше не о чем.

Механизм: обменный аргумент по шагам

Сначала обозначения, они понадобятся во всех доказательствах раздела. Ответ - это МНОЖЕСТВО выбранных элементов; |O| значит «сколько элементов в O», x ∈ O - «x лежит в O», O − o + g - «взять O, убрать оттуда o, добавить g». Значок ∎ в конце означает «на этом доказательство закончено».

ЧТО ДОКАЗЫВАЕМ
    существует оптимальный ответ, СОДЕРЖАЩИЙ наш жадный выбор g
    (а не «g лучше всех» - это другое утверждение, и обычно ложное)

КАК
    1. пусть O - произвольный оптимальный ответ
    2. если g уже в O - доказывать нечего
    3. иначе найди в O элемент o, который «мешает» g
       (у занятий это первое по времени занятие в O)
    4. построй O' = O − o + g
    5. проверь ДВА пункта:
       а) O' по-прежнему ДОПУСТИМ (не нарушает правил задачи)
       б) O' не хуже O по целевой функции
    6. значит O' тоже оптимален и содержит g                  ∎
ВТОРОЙ СПОСОБ: «ЖАДНЫЙ НЕ ОТСТАЁТ» (greedy stays ahead)

    1. выбери МЕРУ, по которой сравниваешь частичные ответы
       (у занятий: время окончания k-го выбранного занятия)
    2. докажи индукцией по k: у жадного эта мера не хуже,
       чем у любого другого допустимого ответа
    3. из «не отстаёт на каждом шаге» следует «не хуже в конце»

когда удобнее: когда ответ - число (сколько элементов, сумма, длина),
а не множество, которое надо перестраивать

Правило

Обменный аргумент доказывает БЕЗОПАСНОСТЬ жадного шага: берём произвольный оптимальный ответ, заменяем в нём один элемент на жадный выбор и проверяем два пункта - что ответ остался допустимым и не стал хуже. Отсюда следует, что существует оптимум, содержащий наш выбор; вместе с оптимальностью подзадачи это даёт индукцию по шагам и оптимальность всего жадного ответа. Доказывать «наш выбор лучший» не надо и обычно нельзя. Альтернатива - «жадный не отстаёт»: выбрать меру частичного ответа и показать индукцией, что по этой мере жадный не хуже любого другого. Если ни одно из двух доказательств не проходит, скорее всего критерий неверен - ищи контрпример среди трёх-четырёх элементов.

Разбор: выбор занятий, доказательство обменом

Критерий: брать занятие с самым ранним КОНЦОМ среди совместимых с уже взятыми.

Утверждение. Пусть g - занятие с самым ранним концом среди всех.
Тогда существует оптимальное расписание, содержащее g.

Доказательство.
    Пусть O - любое оптимальное расписание, |O| = k.
    Если g ∈ O - готово.
    Иначе: отсортируем O по времени и возьмём o - ПЕРВОЕ занятие в O.
    Построим O' = O − o + g.

    (а) допустимость: конец g не позже конца o (g выбран как самый ранний
        по концу среди ВСЕХ занятий, значит и среди O). Остальные занятия O
        начинались не раньше конца o, значит и не раньше конца g -
        пересечений не возникло.
    (б) размер: |O'| = |O| = k - мы заменили одно занятие на одно.

    Значит O' - тоже оптимальное расписание, и g ∈ O'.                 ∎

Обрати внимание, какой именно элемент выбирается для обмена: ПЕРВЫЙ по времени в O. Это не случайность - именно он единственный может мешать g, потому что g заканчивается раньше всех. Если взять для обмена произвольное занятие, пункт (а) не пройдёт.

И сравни это с задачей про файлы из прошлого урока: там для обмена годился ЛЮБОЙ файл оптимума. Разница не в технике, а в задаче: у файлов мешает только суммарный размер, и замена на меньший файл безопасна всегда, а у занятий мешает пересечение по времени, и безопасна замена лишь одного, конкретного занятия. Выбор элемента для обмена - это и есть содержательная часть доказательства; техника одна, а что именно обменивать, каждый раз решается заново.

Вторая половина доказательства - оптимальность подзадачи, и она здесь почти очевидна: после взятия g остаются все занятия, начинающиеся не раньше конца g, и это задача ровно того же вида. Соединяем: по индукции жадный ответ оптимален для любого числа занятий.

цена алгоритма: сортировка по концу Θ(n·log n) + один проход Θ(n)

Разбор: то же, но способом «жадный не отстаёт»

Та же задача, другая техника. Мера: время окончания k-го по счёту выбранного занятия - чем раньше, тем лучше (тем больше места осталось).

Пусть g₁, g₂, ..., g_m - занятия, выбранные жадностью (в порядке выбора),
а o₁, o₂, ..., o_k - любое другое допустимое расписание, отсортированное по времени.

Утверждение (индукция по j): конец g_j <= конец o_j для всех j <= min(m, k).

База: g₁ - занятие с самым ранним концом среди ВСЕХ, значит и среди o₁.

Шаг: пусть конец g_j <= конец o_j. Занятие o_{j+1} начинается не раньше конца o_j,
     то есть не раньше конца g_j - значит оно БЫЛО ДОСТУПНО жадности на шаге j+1.
     Жадность берёт самое раннее по концу из доступных, поэтому
     конец g_{j+1} <= конец o_{j+1}.

Теперь пусть k > m, то есть чужое расписание ДЛИННЕЕ. Тогда o_{m+1}
начинается не раньше конца o_m >= конца g_m - значит оно было доступно
жадности после g_m, и жадность не остановилась бы на m занятиях.
Противоречие. Значит k <= m: жадный ответ не короче любого другого.    ∎

Два доказательства одной теоремы - и это не упражнение ради упражнения. Обменный аргумент удобнее, когда ответ - МНОЖЕСТВО и его можно перестраивать; «не отстаёт» - когда ответ измеряется числом и шаги сравниваются напрямую. В следующей главе пригодятся оба: у расписаний со штрафами естественнее обмен, у кода Хаффмана - тоже обмен, но с перестановкой листьев дерева.

Что ломается без этого

Первое: доказывать «наш выбор самый выгодный» - утверждение и неверное, и недостаточное. Второе: обменять не тот элемент: в доказательстве про занятия годится только ПЕРВОЕ по времени занятие оптимума, иначе допустимость не сохранится. Третье: забыть пункт (а): «размер не изменился» без проверки допустимости не доказывает ничего - можно «улучшить» ответ до недопустимого. Четвёртое: доказать безопасность первого шага и решить, что всё готово: нужна ещё оптимальность подзадачи, то есть что после шага задача того же вида. Пятое: в способе «не отстаёт» выбрать меру, по которой жадный на самом деле отстаёт, и не заметить этого: мера должна быть такой, чтобы из неё следовал ответ (здесь - время окончания, а не, скажем, суммарная длина занятий).

Зачем это в работе

Пять строк доказательства - это то, что отличает «я написал сортировку и проход» от «я знаю, что этот ответ оптимален». На практике полное доказательство пишут редко, но ПРОВЕРКУ обменом делают постоянно, в уме: «а если в идеальном ответе этого элемента нет - смогу я его туда вставить, выкинув один чужой?» Если ответ «нет» или «не знаю» - критерий под подозрением, и дальше либо ищешь контрпример, либо меняешь критерий, либо честно объявляешь алгоритм приближённым. Та же техника работает и в обратную сторону - как инструмент поиска контрпримера: место, где обмен не проходит, обычно и подсказывает, как построить плохой вход. И ещё одно: обменный аргумент уже встречался в курсе. Свойство разреза для минимального остовного дерева (раздел 11) доказывается ровно так: берём любое оптимальное дерево, добавляем наше ребро, выкидываем из образовавшегося цикла ребро не меньшего веса.

Теперь сам

Задача: n задач со временем выполнения t₁ ... tₙ, один процессор. Порядок выбираем мы. Минимизировать СУММУ времён завершения. Жадный критерий - по возрастанию времени выполнения. Докажи обменом, что он оптимален.

Ответ. Пусть O - оптимальный порядок, и в нём есть пара СОСЕДНИХ задач i, j (i раньше j), у которых t_i > t_j. Поменяем их местами.

было:   ... | задача i (t_i) | задача j (t_j) | ...
стало:  ... | задача j (t_j) | задача i (t_i) | ...

пусть до пары прошло время S.
было:   завершения пары  (S + t_i) + (S + t_i + t_j)  = 2S + 2t_i + t_j
стало:  завершения пары  (S + t_j) + (S + t_j + t_i)  = 2S + 2t_j + t_i

разница (было − стало) = 2t_i + t_j − 2t_j − t_i = t_i − t_j > 0

значит после обмена сумма СТРОГО МЕНЬШЕ

Остальные задачи не затронуты: время завершения всех, кто до пары, не изменилось, а всех, кто после, зависит только от суммы t_i + t_j, которая та же. Получили порядок строго лучше оптимального - противоречие. Значит в оптимальном порядке нет соседней пары «длинная раньше короткой», а это и есть порядок по возрастанию.

Заметь, что здесь обмен применён иначе: не «вставим наш элемент в оптимум», а «в оптимуме нет плохой пары соседей». Это разновидность того же аргумента, которую называют обменом соседних элементов, и она особенно удобна, когда ответ - ПОРЯДОК, а не множество. Та же выкладка - основа правила «короткие задачи вперёд», по которому планируют очереди и в операционных системах, и в сервисных центрах.

Главное

Безопасность жадного шага доказывают ОБМЕНОМ: берут произвольный оптимальный ответ O, находят в нём элемент, мешающий жадному выбору g, строят O' = O − o + g и проверяют два пункта - допустимость O' и что он не хуже O. Отсюда: существует оптимум, содержащий g. Для занятий обменивают именно ПЕРВОЕ по времени занятие оптимума, и именно потому, что g заканчивается раньше всех. Вариант для задач, где ответ - порядок: показать, что в оптимуме нет «плохой пары соседей» (так доказывается «короткие задачи вперёд»). Альтернативная техника - «жадный не отстаёт»: выбрать меру частичного ответа и индукцией показать, что жадный по ней не хуже любого другого. Доказательства короткие, но обязательные: без них жадный алгоритм - догадка, а не алгоритм.

Комментарии

Пока нет комментариев. Будь первым!

Оставить комментарий

Комментарий появится после проверки. Email не публикуется. Войти, чтобы не вводить имя каждый раз.