🔴 Сложный ⏱️ 25 минут

Жадные алгоритмы: выбери лучшее прямо сейчас

Жадные алгоритмы: выбери лучшее прямо сейчас

🎯 Зачем это нужно?

Представь, что ты собираешь команду для киберспортивного турнира 🎮. У каждого игрока есть рейтинг, и ты хочешь набрать максимально сильную команду. Жадный подход: “Беру самого сильного из доступных, потом следующего самого сильного, и так далее”.

Жадные алгоритмы работают именно так - на каждом шаге делают локально оптимальный выбор, надеясь получить глобально оптимальное решение!

💼 Где используется:

  • Uber/Яндекс.Такси: назначение ближайших водителей заказам
  • YouTube/TikTok: рекомендации контента (показываем самые релевантные видео)
  • Trading: высокочастотная торговля на бирже
  • Кодирование: алгоритм Хаффмана для сжатия данных

📚 История вопроса

В 1971 году Джек Эдмондс придумал термин “жадный алгоритм” (greedy algorithm). Но сама идея древняя как мир! Еще в Древней Греции торговцы интуитивно использовали жадные стратегии: “Продаю самый дорогой товар из имеющихся”.

Интересно: многие считают жадность плохой чертой, но в алгоритмах она часто приводит к оптимальным решениям! 😄

💡 Интуиция

Жадный = “Бери лучшее из того, что есть СЕЙЧАС”

Аналогия с едой в столовой 🍽️:

  • Жадный подход: Беру самое вкусное блюдо из доступных прямо сейчас
  • Не жадный: Анализирую все возможные комбинации блюд и выбираю оптимальную

Жадность работает быстро, но не всегда дает лучший результат глобально!

[МЕДИА: image_01] Описание: Визуализация жадного выбора на примере дерева решений с локальными оптимумами Промпт: “decision tree diagram showing greedy algorithm choices, local optimal points highlighted in green, global optimum in gold, arrows showing greedy path vs optimal path, modern tech illustration style”

📐 Формальное определение

Жадный алгоритм - это алгоритмический подход для решения задач оптимизации, который:

  1. На каждом шаге выбирает локально оптимальное решение
  2. Никогда не пересматривает свой выбор
  3. Надеется, что последовательность локальных оптимумов приведет к глобальному оптимуму

Структура жадного алгоритма:

def greedy_algorithm(input_data):
    solution = []
    while not is_complete(solution):
        # 1. Генерируем кандидатов
        candidates = generate_candidates(input_data, solution)
        
        # 2. Выбираем лучшего (жадно!)
        best = select_best(candidates)
        
        # 3. Добавляем в решение (без возврата!)
        solution.append(best)
        
        # 4. Обновляем данные
        input_data = update(input_data, best)
    
    return solution

Свойство жадного выбора: если локально оптимальный выбор на каждом шаге приводит к глобально оптимальному решению, то задача имеет greedy choice property.

🔍 Примеры с разбором

Пример 1: Задача о размене монет

Задача: Разменять сумму наименьшим количеством монет.

У нас есть монеты: 50₽, 10₽, 5₽, 1₽. Нужно разменять 67₽.

Жадный подход:

  1. Берем максимальную монету ≤ 67₽ → 50₽ (остаток: 17₽)
  2. Берем максимальную монету ≤ 17₽ → 10₽ (остаток: 7₽)
  3. Берем максимальную монету ≤ 7₽ → 5₽ (остаток: 2₽)
  4. Берем максимальную монету ≤ 2₽ → 1₽ (остаток: 1₽)
  5. Берем максимальную монету ≤ 1₽ → 1₽ (остаток: 0₽)

Результат: 50 + 10 + 5 + 1 + 1 = 5 монет ✅

def coin_change_greedy(amount, coins):
    coins.sort(reverse=True)  # Сортируем по убыванию
    result = []
    
    for coin in coins:
        while amount >= coin:
            result.append(coin)
            amount -= coin
    
    return result

# Пример использования
coins = [50, 10, 5, 1]
print(coin_change_greedy(67, coins))  # [50, 10, 5, 1, 1]

Пример 2: Планирование задач (Activity Selection)

Задача: Выбрать максимальное количество непересекающихся интервалов.

Есть задачи с временами начала и конца:

  • A: [1, 3]
  • B: [2, 4]
  • C: [3, 5]
  • D: [4, 7]

Жадная стратегия: Выбираем задачу с самым ранним временем окончания!

  1. Сортируем по времени окончания: A[1,3], B[2,4], C[3,5], D[4,7]
  2. Выбираем A (заканчивается в 3)
  3. B пересекается с A → пропускаем
  4. C начинается в 3 ≥ 3 → выбираем C (заканчивается в 5)
  5. D начинается в 4 < 5 → пропускаем

Результат: A и C - максимальное количество задач!

[МЕДИА: image_02] Описание: Временная диаграмма с интервалами задач, показывающая жадный выбор Промпт: “timeline diagram showing activity selection problem, overlapping intervals in different colors, greedy selection highlighted, clean modern style, educational visualization”

Пример 3: Алгоритм Дейкстры (кратко)

Задача: Найти кратчайший путь в графе.

Жадная идея: На каждом шаге выбираем вершину с минимальным известным расстоянием!

Это классический пример успешного применения жадной стратегии в ML и computer science.

🎮 Практика

Базовый уровень 🟢

Задача 1: Дана сумма 23₽ и монеты [10, 5, 1]. Сколько монет нужно по жадному алгоритму?

💡 Решение 10 + 10 + 1 + 1 + 1 = 5 монет

Задача 2: Есть задачи: A[1,2], B[2,3], C[1,3]. Какие выберет жадный алгоритм?

💡 Решение Сортируем по времени конца: A[1,2], B[2,3], C[1,3]. Выбираем A и B.

Задача 3: Написать жадный алгоритм для выбора максимальной суммы, если можно взять не более 3 элементов из массива [5, 1, 3, 9, 4].

💡 Решение Сортируем по убыванию: [9, 5, 4, 3, 1]. Берем первые 3: 9 + 5 + 4 = 18.

Продвинутый уровень 🟡

Задача 4: Дан массив интервалов [[1,3], [2,6], [8,10], [15,18]]. Нужно объединить пересекающиеся интервалы жадным способом.

Задача 5: Реализовать жадный алгоритм для задачи о рюкзаке по стоимости/весу (fractional knapsack).

Задача 6: В стратегии машинного обучения нужно выбрать признаки. На каждом шаге добавляем признак, который больше всего улучшает метрику. Это жадный подход?

Челлендж 🔴

Задача 7: Доказать или опровергнуть: жадный алгоритм размена монет всегда оптимален для любого набора монет.

💡 Подсказка Попробуйте монеты [1, 3, 4] и сумму 6. Жадный даст: 4 + 1 + 1 = 3 монеты. А оптимальный?

Задача 8: В градientном спуске мы на каждом шаге делаем шаг в направлении наибольшего убывания функции потерь. Это жадный алгоритм? Всегда ли он находит глобальный минимум?

⚠️ Частые ошибки

Ошибка: Думать, что жадные алгоритмы всегда дают оптимальное решение ✅ Правильно: Жадные алгоритмы быстрые, но оптимальны только для специальных классов задач 💡 Почему: Локальная оптимизация не гарантирует глобального оптимума

Ошибка: Использовать жадный подход там, где нужно dynamic programming
Правильно: Сначала проверить, имеет ли задача greedy choice property 💡 Почему: Классический пример - 0/1 knapsack problem требует DP, а не жадности

Ошибка: Не учитывать сложность сортировки в жадных алгоритмах ✅ Правильно: Сложность часто O(n log n) из-за необходимости сортировки
💡 Почему: Жадный выбор требует упорядоченных данных

Ошибка: Пытаться “улучшить” жадный алгоритм пересмотром решений ✅ Правильно: Жадные алгоритмы по определению не возвращаются назад 💡 Почему: Если нужен пересмотр - используйте backtracking или DP

🎓 Главное запомнить

Суть: На каждом шаге выбираем локально лучший вариант, не пересматривая предыдущие решения

Когда работает: Задачи с greedy choice property - локальные оптимумы ведут к глобальному

Применение: Кратчайшие пути (Дейкстра), планирование задач, некоторые задачи ML

🔗 Связь с другими темами

Откуда пришли: Динамическое программирование (урок 270) - более общий подход, жадность - частный случай

Куда ведет:

  • Алгоритмы на графах (Дейкстра, Краскал, Прим)
  • Feature selection в машинном обучении
  • Оптимизационные стратегии в deep learning

Понял тему? Закрепи в боте! 🚀

Попрактикуйся на задачах и получи персональные рекомендации от AI

💪 Начать тренировку
💬 Есть вопрос? Спроси бота!