Жадный алгоритм

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

Жадный алгоритм (англ. Greedy algorithm) — алгоритм, заключающийся в принятии локально оптимальных решений на каждом этапе, допуская, что конечное решение также окажется оптимальным.

Условия применимости[править | править исходный текст]

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

Принцип жадного выбора[править | править исходный текст]

Говорят, что к оптимизационной задаче применим принцип жадного выбора, если последовательность локально оптимальных выборов даёт глобально оптимальное решение. В типичном случае доказательство оптимальности следует такой схеме:

  1. Доказывается, что жадный выбор на первом шаге не закрывает пути к оптимальному решению: для всякого решения есть другое, согласованное с жадным выбором и не хуже первого.
  2. Показывается, что подзадача, возникающая после жадного выбора на первом шаге, аналогична исходной.
  3. Рассуждение завершается по индукции.

Оптимальность для подзадач[править | править исходный текст]

Говорят, что задача обладает свойством оптимальности для подзадач, если оптимальное решение задачи содержит в себе оптимальные решения для всех её подзадач. Например, в задаче о выборе заявок можно заметить, что если A — оптимальный набор заявок, содержащий заявку номер 1, то A^\prime = A \setminus \left\{1\right\}— оптимальный набор заявок для меньшего множества заявок S^\prime, состоящего из тех заявок, для которых s_i \le f_1.

Примеры[править | править исходный текст]

Размен монет[править | править исходный текст]

Задача. Монетная система некоторого государства состоит из монет достоинством a_1=1 < a_2 < ... < a_n. Требуется выдать сумму S наименьшим возможным количеством монет.

Жадный алгоритм решения этой задачи таков. Берётся наибольшее возможное количество монет достоинства a_n: x_n=\lfloor S/a_n \rfloor. Таким же образом получаем, сколько нужно монет меньшего номинала, и т. д.

Для данной задачи жадный алгоритм не всегда даёт оптимальное решение. Например, сумму в 24 копейки монетами в 1, 5 и 7 коп. жадный алгоритм разменивает так: 7 коп. — 3 шт., 1 коп. — 3 шт., в то время как правильное решение — 7 коп. — 2 шт., 5 коп. — 2 шт. Тем не менее, на всех реальных монетных системах жадный алгоритм даёт правильный ответ. Это связано с тем что сумма двух любых меньших номиналов всегда меньше или равна большему номиналу. Номi-2 + Номi-1 < Номi

Выбор заявок[править | править исходный текст]

Формулировка № 1. Даны n заявок на проведение занятий в некоторой аудитории. В каждой заявке указаны начало и конец занятия (s_i и f_i для i-й заявки). В случае пересечения заявок можно удовлетворить лишь одну из них. Заявки с номерами i и j совместны, если интервалы [s_i, f_i) и [s_j, f_j) не пересекаются (то есть f_i \le s_j или f_j \le s_i). Задача о выборе заявок состоит в том, чтобы набрать максимальное количество совместных друг с другом заявок.

Формулировка № 2. На конференции, чтобы отвести больше времени на неформальное общение, различные секции разнесли по разным аудиториям. Учёный с чрезвычайно широкими интересами хочет посетить несколько докладов, проходящих в разных секциях. Известно начало s_i и конец f_i каждого доклада. Определить, какое максимальное количество докладов можно посетить.

Приведём жадный алгоритм, решающий данную задачу. При этом полагаем, что заявки упорядочены в порядке возрастания времени окончания. Если это не так, то можно отсортировать их за время O(n \log n); заявки с одинаковым временем конца располагаем в произвольном порядке.

Activity-Selector(s,f)

  1. n \leftarrow length[s]
  2. A \leftarrow  \left\{1\right\}
  3. j \leftarrow 1
  4. for i \leftarrow 2 to n do
    if s_i \ge f_j then
    A \leftarrow A \cup \{i\}
    j \leftarrow i
  5. return A

На вход данному алгоритму подаются массивы начала и окончания занятий. Множество A состоит из номеров выбранных заявок, а j — номер последней заявки. Жадный алгоритм ищет заявку, начинающуюся не ранее окончания j-той, затем найденную заявку включает в A, а j присваивает её номер. Таким образом, каждый раз мы выбираем то (ещё не начавшееся) занятие, до конца которого осталось меньше всего времени.

Алгоритм работает за O(n \log n+n), то есть сортировка плюс выборка. На каждом шаге выбирается наилучшее решение. Покажем, что в итоге получится оптимум.

Доказательство. Заметим, что все заявки отсортированы по неубыванию времени окончания. Заявка номер 1, очевидно, входит в оптимум (если нет, то заменим самую раннюю заявку в оптимуме на неё, от этого хуже не станет). Выкинув все заявки, противоречащие первой, получим исходную задачу с меньшим количеством заявок. Рассуждая по индукции, аналогичным образом приходим к оптимальному решению.

Другие жадные алгоритмы[править | править исходный текст]

Обобщением жадных алгоритмов является алгоритм Радо — Эдмондса.

Задачи, в которых жадные алгоритмы не дают оптимального решения[править | править исходный текст]

Для ряда задач, относящихся к классу NP, жадные алгоритмы не дают оптимального решения. К ним относятся:

Тем не менее, в ряде задач жадные алгоритмы дают неплохие приближённые решения.

См. также[править | править исходный текст]

Ссылки[править | править исходный текст]

Литература[править | править исходный текст]