Алгоритм Литтла: решаем задачу коммивояжёра

Алгоритм Литтла - это конкретная реализация метода ветвей и границ для задачи коммивояжёра, предложенная Литтлом, Мурти, Суини и Кэрелом в 1963 году. Он отвечает на тот же вопрос - как объехать все города по разу и вернуться в исходный с минимальной длиной маршрута, - но делает это не перебором всех циклов, а умной работой с матрицей расстояний: приводит её, считает штрафы у нулевых клеток и строит дерево ветвления, отсекая заведомо проигрышные ветви. Ниже разберём схему алгоритма Литтла пошагово, с формулами и типичными ловушками.
Что такое алгоритм Литтла
Алгоритм Литтла работает с квадратной матрицей расстояний , где - стоимость переезда из города в город , а на диагонали стоит , потому что ехать из города в самого себя нельзя. Это частный случай общей схемы branch and bound, но с двумя характерными именно для него приёмами: оценка снизу строится через приведение матрицы, а ребро для ветвления выбирается по максимальному штрафу нулевой клетки.
Алгоритм Литтла даёт точный оптимум, а не приближение. Его смысл - заменить полный перебор направленным поиском по дереву, где каждый узел отвечает за множество маршрутов с уже принятыми решениями «такое-то ребро входит / не входит в путь». Если идею ветвей и границ хочется увидеть в более общем виде, есть отдельный разбор метода ветвей и границ для задачи коммивояжёра - алгоритм Литтла является его классической матричной формой.
Прежде чем считать вручную, прогоните свою матрицу через инструмент ниже - он соберёт корректную постановку и попросит модель показать дерево решения по шагам.
Приведение матрицы и нижняя граница
Первый шаг алгоритма Литтла - приведение матрицы. В любом замкнутом маршруте из каждого города ровно один выезд и ровно один въезд. Значит, можно из каждой строки вычесть её минимальный элемент, а затем из каждого столбца - его минимум: структура допустимых решений не изменится, изменится лишь точка отсчёта стоимости.
Если - минимум строки , а после вычитания строк - минимум столбца , то нижняя граница корня дерева равна
Эта величина - гарантированный минимум: ни один полный цикл не может стоить меньше . После приведения в каждой строке и каждом столбце появляется хотя бы один ноль - именно эти нулевые клетки становятся кандидатами на включение в маршрут.
Контроль приведения: после него и в каждой строке, и в каждом столбце обязан стоять хотя бы один ноль. Нет нуля где-то - приведение не доведено до конца.
Штрафы нулевых клеток
Вот здесь начинается «фирменная» часть алгоритма Литтла. Для каждой нулевой клетки считают штраф - он показывает, насколько вырастет нижняя граница, если ребро в маршрут НЕ включать. Штраф равен сумме минимального оставшегося элемента строки и минимального оставшегося элемента столбца , причём сама клетка из этих минимумов исключается:
Логика простая: если ребро исключить (поставить в клетку ), то выезд из города и въезд в город всё равно придётся оплатить, и минимально это обойдётся в . Поэтому исключение клетки с большим штрафом дорого наказывается - её выгоднее включить.
Выбор ребра и ветвление
Для ветвления алгоритм Литтла выбирает нулевую клетку с максимальным штрафом . Это эвристика, направляющая поиск: включение такого ребра перспективнее всего, а его исключение поднимает границу сильнее всего. Выбранное ребро порождает две дочерние ветви.
- Ребро включается. Из матрицы вычёркивают строку и столбец , в клетку ставят (чтобы не замкнулся преждевременный подцикл), и уменьшенную матрицу снова приводят. Нижняя граница ветви = граница родителя плюс сумма новых приведений.
- Ребро исключается. В клетку ставят и приводят матрицу. Нижняя граница этой ветви = граница родителя плюс штраф .
Алгоритм всегда раскрывает живую ветвь с наименьшей нижней границей (стратегия «лучший первым»). Когда матрица сжимается до , оба оставшихся ребра определяются однозначно, маршрут замыкается в полный цикл, и его стоимость становится кандидатом в рекорд .
Отсечение по рекорду
Как только в дереве найден хотя бы один полный маршрут стоимостью , любая живая ветвь с нижней границей закрывается: лучшего решения внутри неё уже не будет. Это и есть «граница» в названии метода. Чем раньше найден хороший рекорд, тем агрессивнее идёт отсечение, поэтому на практике алгоритм Литтла иногда стартует с грубой оценки «ближайшим соседом», чтобы получить начальный пораньше.
Поиск завершается, когда не остаётся живых ветвей с границей меньше рекорда. Текущий рекорд при этом гарантированно оптимален. Идея «постепенно улучшаемой оценки» роднит алгоритм Литтла с другими методами на графах - например, с алгоритмом Беллмана-Форда для кратчайших путей, где оценки расстояний тоже последовательно подтягиваются к точным.
Сложность и практические границы
В худшем случае алгоритм Литтла сохраняет экспоненциальную сложность: отсечения не дают гарантий по числу раскрытых узлов, и теоретически дерево может разрастись почти как полный перебор. Но на реальных данных всё иначе - качественная нижняя граница, полученная приведением, режет огромную долю ветвей, и матрицы на – городов решаются точно за разумное время.
Узким местом раньше становится не время, а память: при стратегии «лучший первым» в очереди живых ветвей одновременно висит много частичных матриц. Поэтому на практике комбинируют подходы - сначала идут вглубь по самой перспективной ветви, чтобы быстро получить рекорд , затем переключаются на «лучший первым» с уже агрессивным отсечением. Ещё один инженерный рычаг - пересчитывать границу инкрементно: не приводить всю матрицу заново на каждом узле, а корректировать её после удаления одной строки и одного столбца. Для больших переходят к более сильным релаксациям (линейное программирование, -дерево Хелда-Карпа) или к эвристикам, но алгоритм Литтла остаётся базовым «честным» способом получить доказуемо оптимальный маршрут.
Частые ошибки
- Забывают на диагонали. Без этого алгоритм Литтла «разрешит» переезд города в самого себя и испортит нижнюю границу с первого же приведения.
- Не блокируют подцикл. При включении ребра обязательно ставят в , а в длинных цепочках - в клетку, замыкающую уже собранный частичный путь, иначе маршрут распадётся на несколько мелких циклов.
- Берут первый минимум вместо второго в штрафе. Штраф нулевой клетки считается по минимумам строки и столбца без самой клетки; саму нулевую клетку из подсчёта исключают.
- Путают ветви местами. Прибавка штрафа идёт к ветви, где ребро исключается; к ветви включения прибавляется сумма новых приведений уменьшенной матрицы.
- Раскрывают узлы в произвольном порядке. Без стратегии «лучший первым» рекорд находится поздно, отсечение почти не работает, и дерево раздувается.
FAQ
Чем алгоритм Литтла отличается от общего метода ветвей и границ? Алгоритм Литтла - это конкретная матричная реализация метода для задачи коммивояжёра: нижняя граница берётся приведением матрицы, а ребро для ветвления выбирается по максимальному штрафу нулевой клетки. Общая схема ветвей и границ этих деталей не фиксирует.
Зачем приводить матрицу расстояний? Приведение по строкам и столбцам даёт стартовую нижнюю границу даром: сумма вычтенных минимумов - гарантированный минимум стоимости любого полного маршрута. Без неё границы были бы слабыми, и отсечение почти не срабатывало бы.
Работает ли алгоритм Литтла для несимметричной задачи? Да. Он изначально оперирует произвольной матрицей - приведение, штрафы и блокировка подциклов симметрии не требуют. Симметрия лишь уменьшает число различных маршрутов вдвое, до .
Коротко
Алгоритм Литтла решает задачу коммивояжёра точно методом ветвей и границ: приведение матрицы даёт нижнюю границу, штрафы нулевых клеток указывают ребро для ветвления, дерево делится на ветви «ребро включено / исключено», а найденный рекорд позволяет отсекать все ветви с границей не меньше его. Так алгоритм добирается до оптимального маршрута, раскрывая лишь малую долю всех вариантов. </content> </invoke>
Читайте также

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

Алгоритм Рабина-Карпа: поиск подстроки за O(n+m)
Разбираем алгоритм Рабина-Карпа: как полиномиальный хеш и скользящее окно ускоряют поиск подстроки до O(n+m) в среднем, почему бывают ложные совпадения и при чём тут плагиат.

Распределение Фишера критические значения: как искать F-квантили
Распределение Фишера и его критические значения: что такое F-распределение, как читать таблицу критических значений по двум степеням свободы, как применять F-квантили в F-тесте на равенство дисперсий и в дисперсионном анализе.