Жадібний алгоритм
Жа́дібний алгори́тм (англ. Greedy algorithm) — простий і прямолінійний евристичний алгоритм, який приймає найкраще рішення, виходячи з наявних на кожному етапі даних,[1] не зважаючи на можливі наслідки, сподіваючись урешті-решт отримати оптимальний розв'язок. Легкий в реалізації і часто дуже ефективний за часом виконання. Багато задач не можуть бути розв'язані за його допомогою.
Наприклад, використання жадібної стратегії для задачі комівояжера породжує такий алгоритм: «На кожному етапі вибирати найближче з невідвіданих міст».
Зазвичай, жадібний алгоритм базується на п'яти принципах:
- Набір можливих варіантів, з яких робиться вибір;
- Функція вибору, за допомогою якої знаходиться найкращий варіант, який буде додано до розв'язку;
- Функція придатності, яка визначає придатність отриманого набору;
- Функція цілі, передає значення розв'язку або частковому розв'язку;
- Функція розв'язку, яка вказує на те, що кінцевий розв'язок знайдено.
Придатний набір варіантів — такий, що обіцяє не просто отримання розв'язку, а отримання оптимального розв'язку задачі.
На відміну від динамічного програмування, за якого задача розв'язується знизу догори, за жадібної стратегії це робиться згори донизу, шляхом здійснення одного жадібного вибору за іншим, зведенням великої задачі до малої.
Жадібний алгоритм добре розв'язує деякі задачі, а інші — ні. Більшість задач, для яких він спрацьовує добре, мають дві властивості: по-перше, до них можливо застосувати принцип жадібного вибору, по-друге, вони мають властивість оптимальної підструктури.
До оптимізаційної задачі можна застосувати принцип жадібного вибору, якщо послідовність локально оптимальних виборів дає глобально оптимальний розв'язок. В типовому випадку доведення оптимальності здійснюється за такою схемою: спочатку доводиться, що жадібний вибір на першому етапі не унеможливлює шляху до оптимального розв'язку: для будь-якого розв'язку є інший, узгоджений із жадібним і не гірший від першого. Далі доводиться, що підзадача, яка виникла після жадібного вибору на першому етапі, аналогічна початковій, і міркування закінчується за індукцією. Інакше кажучи, за жадібного алгоритму ніколи не переглядаються попередні вибори для здійснення наступного, на відміну від динамічного програмування.
«Задача має оптимальну підструктуру, якщо оптимальний розв'язок задачі містить оптимальний розв'язок для підзадач»[2]. Інакше кажучи, задача має оптимальну підструктуру, якщо кожен наступний крок веде до оптимального розв'язку. Прикладом «неоптимальної підструктури» може бути ситуація в шахах, коли взяття ферзя (хороший наступний крок) веде до програшу партії в цілому.
Жадібні алгоритми можна охарактеризувати як «короткозорі» і «невідновлювані». Вони ідеальні лише для задач з «оптимальною підструктурою». Попри це, жадібні алгоритми найкраще підходять для простих задач. Для багатьох інших задач жадібні алгоритми зазнають невдачі у продукуванні оптимального розв'язку, і можуть навіть видати найгірший з можливих розв'язків. Один з прикладів — алгоритм найближчого сусіднього міста, згаданий вище.[3]
Задача. Монетна система деякої держави складається з монет вартістю . Вимагається видати суму S найменшою можливою кількістю монет.
Жадібний алгоритм розв'язання цієї задачі такий. Беремо найбільшу можливу кількість монет вартості : . Так само знаходимо скільки потрібно монет меншого номіналу і т. д.
Для цієї задачі жадібний алгоритм не завжди дає правильний розв'язок. Наприклад, суму 10 копійок монетами вартістю 1, 5 і 6 коп. жадібний алгоритм розміняє так: 6 коп. — 1 шт., 1 коп. — 4 шт., в той час як правильний розв'язок — 2 монети по 5 копійок. Проте, на всіх реальних монетних системах жадібний алгоритм видає правильну відповідь.
Задача. На конференції, щоб відвести більше часу на неформальне спілкування, різні секції рознесли по різних аудиторіях. Вчений із надзвичайно широкими інтересами бажає відвідати декілька доповідей у різних секціях. Відомі початок і кінець кожної доповіді. Визначити, яку найбільшу кількість доповідей можна відвідати.
Наведемо жадібний алгоритм, який розв'язує цю задачу. При цьому вважатимемо, що заявки впорядковано за зростанням часу закінчення. Якщо це не так, то можна відсортувати їх за час ; заявки з однаковим часом закінчення розташовуємо в довільному порядку.
Activity-Selector(s,f)
-
length[s]
for
to n
do if
then
∪ {i}
return A
На вхід алгоритму подаються масиви початків і закінчень доповідей. Множина А складається з номерів вибраних заявок, а j — номер наступної заявки. Жадібний алгоритм шукає заявку, що починається не раніше від закінчення j-ї, потім знайдену заявку включає в А, а j присвоює її номер.
Алгоритм працює за , тобто за складністю сортування, оскільки вибірка має меншу складність . На кожному кроці вибирається найкращий розв'язок. Покажемо, що результатом буде оптимальний розв'язок.
Доведення. Зауважимо, що всі заявки відсортовано за неспаданням часу завершення. Заявка номер 1 однозначно входить до оптимального розв'язку, (якщо ні, замінимо найпершу заявку в оптимумі нею, гірше від цього не стане). Відкинувши всі заявки, що суперечать першій, отримаємо початкову задачу з меншою кількістю заявок. Розмірковуючи індуктивно, приходимо до оптимального розв'язку.
- ↑ Black, Paul E. (2 лютого 2005). greedy algorithm. Dictionary of Algorithms and Data Structures. U.S. National Institute of Standards and Technology (NIST). Архів оригіналу за 23 березня 2019. Процитовано 17 серпня 2012.
- ↑ Т. Кормен; Ч. Лейзерсон; Р. Рівест; К. Стайн (2009) [1990]. 16. Жадібні алгоритми. Вступ до алгоритмів (вид. 3rd). MIT Press і McGraw-Hill. ISBN 0-262-03384-4.
- ↑ Gutin, Gregory; Yeo, Anders; Zverovich, Alexey (2002). Traveling salesman should not be greedy: Domination analysis of greedy-type heuristics for the TSP. Discrete Applied Mathematics. 117 (1–3): 81—86. doi:10.1016/S0166-218X(01)00195-0.
- Т. Кормен; Ч. Лейзерсон; Р. Рівест; К. Стайн (2009) [1990]. 16. Жадібні алгоритми. Вступ до алгоритмів (вид. 3rd). MIT Press і McGraw-Hill. ISBN 0-262-03384-4.
- Greedy algorithm visualization [Архівовано 30 серпня 2009 у Wayback Machine.] Візуалізація задачі N ферзів (розташувати на дошці N*N, так щоб жоден з них не атакував іншого).