0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>В прошлом уроке мы познакомились с задачей коммивояжера и решили ее с помощью перебора.</p>
1
<p>В прошлом уроке мы познакомились с задачей коммивояжера и решили ее с помощью перебора.</p>
2
<p>Перебор имеет алгоритмическую сложность O(n!), что очень медленно. Более эффективный способ решать задачи на графах - метод ветвей и границ.</p>
2
<p>Перебор имеет алгоритмическую сложность O(n!), что очень медленно. Более эффективный способ решать задачи на графах - метод ветвей и границ.</p>
3
<p>Он применяется к широкому классу задач на графах и для решения конкретной задачи его нужно адаптировать.</p>
3
<p>Он применяется к широкому классу задач на графах и для решения конкретной задачи его нужно адаптировать.</p>
4
<p>Алгоритм Литтла - известная адаптаций метода ветвей и границ для решения задачи коммивояжера. Его разработала группа ученых и программистов под руководством профессора Джона Д. К. Литтла. Статья с описанием алгоритма была опубликована в 1963 году.</p>
4
<p>Алгоритм Литтла - известная адаптаций метода ветвей и границ для решения задачи коммивояжера. Его разработала группа ученых и программистов под руководством профессора Джона Д. К. Литтла. Статья с описанием алгоритма была опубликована в 1963 году.</p>
5
<h2>Как работает алгоритм Литтла</h2>
5
<h2>Как работает алгоритм Литтла</h2>
6
<p>Алгоритм Литтла довольно громоздкий, так что мы будем знакомиться с ним по частям. Для представления графа в алгоритме используется матрица смежности. В качестве иллюстрации мы будем использовать матрицу из оригинальной публикации 1963 года:</p>
6
<p>Алгоритм Литтла довольно громоздкий, так что мы будем знакомиться с ним по частям. Для представления графа в алгоритме используется матрица смежности. В качестве иллюстрации мы будем использовать матрицу из оригинальной публикации 1963 года:</p>
7
<p>У нас есть шесть городов, поэтому в матрице шесть строк и шесть столбцов. Обсудим эту матрицу подробнее:</p>
7
<p>У нас есть шесть городов, поэтому в матрице шесть строк и шесть столбцов. Обсудим эту матрицу подробнее:</p>
8
<ul><li>Числа в матрице - это стоимость переезда из одного города в другой. Это условная цифра, которая может обозначать цену бензина, расстояние между городами или время езды.</li>
8
<ul><li>Числа в матрице - это стоимость переезда из одного города в другой. Это условная цифра, которая может обозначать цену бензина, расстояние между городами или время езды.</li>
9
<li>Обратите внимание, что граф ориентированный. Это значит, что стоимость перемещения из города A в город B и из города B в город A необязательно равны между собой. В неориентированном графе эти стоимости совпадают.</li>
9
<li>Обратите внимание, что граф ориентированный. Это значит, что стоимость перемещения из города A в город B и из города B в город A необязательно равны между собой. В неориентированном графе эти стоимости совпадают.</li>
10
</ul><p>Для примера рассмотрим дорогу между городами 1 и 4. Находим соответствующие столбцы и строки в матрице и видим два разных числа:</p>
10
</ul><p>Для примера рассмотрим дорогу между городами 1 и 4. Находим соответствующие столбцы и строки в матрице и видим два разных числа:</p>
11
<ul><li>16 в первой строке в четвертом столбце - это стоимость перемещения из города 1 в город 4.</li>
11
<ul><li>16 в первой строке в четвертом столбце - это стоимость перемещения из города 1 в город 4.</li>
12
<li>21 в четвертой строке в первом столбце - это стоимость перемещения из города 4 в город 1.</li>
12
<li>21 в четвертой строке в первом столбце - это стоимость перемещения из города 4 в город 1.</li>
13
</ul><p>Некоторые ребра в графе не могут существовать физически - например, нельзя переместиться в тот же самый город. В матрице смежности таким переездам соответствуют ячейки:</p>
13
</ul><p>Некоторые ребра в графе не могут существовать физически - например, нельзя переместиться в тот же самый город. В матрице смежности таким переездам соответствуют ячейки:</p>
14
<ul><li>В первой строке первом столбце</li>
14
<ul><li>В первой строке первом столбце</li>
15
<li>Во второй строке втором столбце</li>
15
<li>Во второй строке втором столбце</li>
16
<li>И так далее</li>
16
<li>И так далее</li>
17
</ul><p>Чтобы отличить невозможные переезды от возможных, мы придумаем для них особое обозначение.</p>
17
</ul><p>Чтобы отличить невозможные переезды от возможных, мы придумаем для них особое обозначение.</p>
18
<p>В коде на JavaScript можно использовать константу Infinity - она соответствует бесконечности, которая больше любого конечного значения.</p>
18
<p>В коде на JavaScript можно использовать константу Infinity - она соответствует бесконечности, которая больше любого конечного значения.</p>
19
<p>На иллюстрациях мы будем писать знак ∞ - символ бесконечности.</p>
19
<p>На иллюстрациях мы будем писать знак ∞ - символ бесконечности.</p>
20
<p>В матрице смежности маршрут записывается как последовательность переездов r:</p>
20
<p>В матрице смежности маршрут записывается как последовательность переездов r:</p>
21
<p>Длина этого маршрута l равна:</p>
21
<p>Длина этого маршрута l равна:</p>
22
<p>Каждый город встречается в этом списке ровно два раза:</p>
22
<p>Каждый город встречается в этом списке ровно два раза:</p>
23
<ul><li>В строке - точка отправления</li>
23
<ul><li>В строке - точка отправления</li>
24
<li>В столбце - точка прибытия</li>
24
<li>В столбце - точка прибытия</li>
25
</ul><p>Это не совпадение - по условиям задачи, коммивояжер должен посетить каждый город ровно один раз. Мы можем отметить ребра маршрута на матрице смежности и увидеть, что в каждой строке и каждом столбце находится ровно одно ребро:</p>
25
</ul><p>Это не совпадение - по условиям задачи, коммивояжер должен посетить каждый город ровно один раз. Мы можем отметить ребра маршрута на матрице смежности и увидеть, что в каждой строке и каждом столбце находится ровно одно ребро:</p>
26
<p>Это утверждение верно для всех маршрутов, удовлетворяющих условию задачи коммивояжера. Из этого следует два интересных факта:</p>
26
<p>Это утверждение верно для всех маршрутов, удовлетворяющих условию задачи коммивояжера. Из этого следует два интересных факта:</p>
27
<ul><li>Если из всех элементов строки или столбца вычесть одно и то же число, то все маршруты сократятся на это число</li>
27
<ul><li>Если из всех элементов строки или столбца вычесть одно и то же число, то все маршруты сократятся на это число</li>
28
<li>После такой модификации самый короткий маршрут останется самым коротким, а самый длинный - самым длинным</li>
28
<li>После такой модификации самый короткий маршрут останется самым коротким, а самый длинный - самым длинным</li>
29
</ul><p>Алгоритм Литтла использует эти свойства для вычисления нижней границы.</p>
29
</ul><p>Алгоритм Литтла использует эти свойства для вычисления нижней границы.</p>
30
<h3>Нижняя граница</h3>
30
<h3>Нижняя граница</h3>
31
<p>Обозначим длину кратчайшего маршрута как l_min. Эта длина не может быть меньше нуля, потому что в каждой ячейке матрицы находится положительные числа или ноль.</p>
31
<p>Обозначим длину кратчайшего маршрута как l_min. Эта длина не может быть меньше нуля, потому что в каждой ячейке матрицы находится положительные числа или ноль.</p>
32
<p>Возьмем число a. Если мы вычтем его из всех чисел строки или всех чисел столбца, то все маршруты сократятся на a.</p>
32
<p>Возьмем число a. Если мы вычтем его из всех чисел строки или всех чисел столбца, то все маршруты сократятся на a.</p>
33
<p>Если при этом все элементы в матрице останутся неотрицательными, то и новая длина маршрута будет больше нуля:</p>
33
<p>Если при этом все элементы в матрице останутся неотрицательными, то и новая длина маршрута будет больше нуля:</p>
34
<ul><li>l_min - a >= 0</li>
34
<ul><li>l_min - a >= 0</li>
35
<li>или l_min >= a</li>
35
<li>или l_min >= a</li>
36
</ul><p>Возьмем нашу матрицу и найдем минимальное число в каждой строке. Запишем его справа от строки:</p>
36
</ul><p>Возьмем нашу матрицу и найдем минимальное число в каждой строке. Запишем его справа от строки:</p>
37
<p>Вычтем из каждой строки минимальное число. Обратите внимание, что после такого вычитания все ячейки в матрице останутся неотрицательными:</p>
37
<p>Вычтем из каждой строки минимальное число. Обратите внимание, что после такого вычитания все ячейки в матрице останутся неотрицательными:</p>
38
<p>При этом минимальная длина будет больше суммы чисел, которые мы вычли:</p>
38
<p>При этом минимальная длина будет больше суммы чисел, которые мы вычли:</p>
39
<p>l_min >= 16+1+0+16+5</p>
39
<p>l_min >= 16+1+0+16+5</p>
40
<p>Такая операция в алгоритме Литтла называется<strong>редукцией по строкам</strong>.</p>
40
<p>Такая операция в алгоритме Литтла называется<strong>редукцией по строкам</strong>.</p>
41
<p>Как мы говорили выше, подобную редукцию можно сделать и по столбцам. Найдем минимальное число в каждом столбце. Запишем его под столбцом:</p>
41
<p>Как мы говорили выше, подобную редукцию можно сделать и по столбцам. Найдем минимальное число в каждом столбце. Запишем его под столбцом:</p>
42
<p>Выполним<strong>редукцию столбцов</strong>- вычтем минимальное число из каждого столбца:</p>
42
<p>Выполним<strong>редукцию столбцов</strong>- вычтем минимальное число из каждого столбца:</p>
43
<p>Все числа в матрице все еще неотрицательные, поэтому можно утверждать следующее:</p>
43
<p>Все числа в матрице все еще неотрицательные, поэтому можно утверждать следующее:</p>
44
<ul><li>l_min >= (16+1+0+16+5)+(5+0+0+0+0+0)</li>
44
<ul><li>l_min >= (16+1+0+16+5)+(5+0+0+0+0+0)</li>
45
<li>l_min >= 43+5</li>
45
<li>l_min >= 43+5</li>
46
<li>l_min >= 48</li>
46
<li>l_min >= 48</li>
47
</ul><p>Таким образом, кратчайший маршрут в графе не может быть меньше 48. Cледовательно, 48 - это и есть<strong>нижняя оценка длины маршрута</strong>.</p>
47
</ul><p>Таким образом, кратчайший маршрут в графе не может быть меньше 48. Cледовательно, 48 - это и есть<strong>нижняя оценка длины маршрута</strong>.</p>
48
<h3>Ветвление</h3>
48
<h3>Ветвление</h3>
49
<p>На следующем шаге построим два поддерева. В начале работы алгоритма наш единственный узел - корень дерева, которое содержит все возможные маршруты:</p>
49
<p>На следующем шаге построим два поддерева. В начале работы алгоритма наш единственный узел - корень дерева, которое содержит все возможные маршруты:</p>
50
<p>Сейчас мы знаем два факта:</p>
50
<p>Сейчас мы знаем два факта:</p>
51
<ul><li>Нижняя граница длины маршрута в этом дереве равна 48</li>
51
<ul><li>Нижняя граница длины маршрута в этом дереве равна 48</li>
52
<li>Пока у нас пока нет никакого маршрута, даже частичного</li>
52
<li>Пока у нас пока нет никакого маршрута, даже частичного</li>
53
</ul><p>Предположим, в качестве очередного ребра маршрута мы выбрали 1-4. Построим два дочерних поддерева:</p>
53
</ul><p>Предположим, в качестве очередного ребра маршрута мы выбрали 1-4. Построим два дочерних поддерева:</p>
54
<p>На половинах дерева мы видим два варианта:</p>
54
<p>На половинах дерева мы видим два варианта:</p>
55
<ul><li>Поддерево справа содержит маршруты, где есть ребро 1-4</li>
55
<ul><li>Поддерево справа содержит маршруты, где есть ребро 1-4</li>
56
<li>Поддерево слева - маршруты, где его нет</li>
56
<li>Поддерево слева - маршруты, где его нет</li>
57
</ul><p>Ребро 1-4 в левом узле помечено красным цветом, который будет означать, что ребро отсутствует. В фигурных скобках записываем маршрут, построенный к настоящему моменту.</p>
57
</ul><p>Ребро 1-4 в левом узле помечено красным цветом, который будет означать, что ребро отсутствует. В фигурных скобках записываем маршрут, построенный к настоящему моменту.</p>
58
<h3>Левое поддерево</h3>
58
<h3>Левое поддерево</h3>
59
<p>Посмотрим, как изменится нижняя оценка для левого поддерева. Взглянем на редуцированную матрицу и выделим цветом ячейку, которая соответствует ребру 1-4:</p>
59
<p>Посмотрим, как изменится нижняя оценка для левого поддерева. Взглянем на редуцированную матрицу и выделим цветом ячейку, которая соответствует ребру 1-4:</p>
60
<p>Рассмотрим каждую точку по отдельности. Сначала обсудим город 1:</p>
60
<p>Рассмотрим каждую точку по отдельности. Сначала обсудим город 1:</p>
61
<ul><li>Из него можно приехать в города 2,3,4,5 и 6</li>
61
<ul><li>Из него можно приехать в города 2,3,4,5 и 6</li>
62
<li>Исключаем ребро 1-4 из маршрута и оставим города 2, 3, 5 и 6</li>
62
<li>Исключаем ребро 1-4 из маршрута и оставим города 2, 3, 5 и 6</li>
63
<li>Стоимость переезда в эти города равна 11, 27, 14 и 10</li>
63
<li>Стоимость переезда в эти города равна 11, 27, 14 и 10</li>
64
<li>Куда бы мы не переехали, стоимость не может быть меньше 10 - это число мы видим в синей ячейке в первой строке</li>
64
<li>Куда бы мы не переехали, стоимость не может быть меньше 10 - это число мы видим в синей ячейке в первой строке</li>
65
</ul><p>Перейдем к городу 4:</p>
65
</ul><p>Перейдем к городу 4:</p>
66
<ul><li>Из него можно приехать в города 1, 2, 3, 5 и 6</li>
66
<ul><li>Из него можно приехать в города 1, 2, 3, 5 и 6</li>
67
<li>Исключаем ребро 1-4 и оставляем города 2, 3, 5 и 6</li>
67
<li>Исключаем ребро 1-4 и оставляем города 2, 3, 5 и 6</li>
68
<li>Стоимость переезда из этих городов равна 0, 35, 43 и 4</li>
68
<li>Стоимость переезда из этих городов равна 0, 35, 43 и 4</li>
69
<li>Откуда бы мы не переехали, стоимость не может быть меньше 0 - это число мы видим в синей ячейке в четвертом столбце</li>
69
<li>Откуда бы мы не переехали, стоимость не может быть меньше 0 - это число мы видим в синей ячейке в четвертом столбце</li>
70
</ul><p>В итоге мы приходим к выводу - мы увеличим редуцированный маршрут минимум на 10+0 в двух случаях:</p>
70
</ul><p>В итоге мы приходим к выводу - мы увеличим редуцированный маршрут минимум на 10+0 в двух случаях:</p>
71
<ul><li>Уехав из города 1 в любой город, кроме 4</li>
71
<ul><li>Уехав из города 1 в любой город, кроме 4</li>
72
<li>Приехав в город 4 из любого города, кроме 1</li>
72
<li>Приехав в город 4 из любого города, кроме 1</li>
73
</ul><p>В то же время, если бы мы воспользовались ребром 1-4, редуцированный маршрут остался бы прежним. Так произошло бы, потому что в ячейке на пересечении первой строки и четвертого столбца сейчас находится 0.</p>
73
</ul><p>В то же время, если бы мы воспользовались ребром 1-4, редуцированный маршрут остался бы прежним. Так произошло бы, потому что в ячейке на пересечении первой строки и четвертого столбца сейчас находится 0.</p>
74
<p>Можно сказать, что 10 - это штраф за отказ от ребра 1-4. Нам известна нижняя граница кратчайшего пути - 48. Без ребра 1-4 она увеличится на 10 и станет равна 48+10=58:</p>
74
<p>Можно сказать, что 10 - это штраф за отказ от ребра 1-4. Нам известна нижняя граница кратчайшего пути - 48. Без ребра 1-4 она увеличится на 10 и станет равна 48+10=58:</p>
75
<p>Предположим, на одном из этапов мы достроим одну из ветвей дерева до конца и получим вариант маршрута с длиной 56.</p>
75
<p>Предположим, на одном из этапов мы достроим одну из ветвей дерева до конца и получим вариант маршрута с длиной 56.</p>
76
<p>Число 58 больше 56, поэтому мы можем игнорировать левое поддерево - маршрут с длиной 56 заведомо короче всех его маршрутов.</p>
76
<p>Число 58 больше 56, поэтому мы можем игнорировать левое поддерево - маршрут с длиной 56 заведомо короче всех его маршрутов.</p>
77
<p>Чем выше нижняя граница в поддереве, тем больше шансов, что поддерево удастся отсечь. Именно поэтому полезно выбирать ребро с небольшим штрафом.</p>
77
<p>Чем выше нижняя граница в поддереве, тем больше шансов, что поддерево удастся отсечь. Именно поэтому полезно выбирать ребро с небольшим штрафом.</p>
78
<p><strong>Штраф для элемента матрицы</strong>- это сумма минимумов в той же строке и том же столбце. Сам элемент учитывать не надо.</p>
78
<p><strong>Штраф для элемента матрицы</strong>- это сумма минимумов в той же строке и том же столбце. Сам элемент учитывать не надо.</p>
79
<p>Если мы будем выбирать элементы 0, минимумами будут нули для которых суммарный штраф также будет равен 0. Чтобы найти ребро с наибольшим штрафом, достаточно проверять только нулевые элементы матрицы:</p>
79
<p>Если мы будем выбирать элементы 0, минимумами будут нули для которых суммарный штраф также будет равен 0. Чтобы найти ребро с наибольшим штрафом, достаточно проверять только нулевые элементы матрицы:</p>
80
<p>На рисунке цветом выделены все нулевые элементы. Рядом с каждым записан суммарный штраф. Максимальный штраф 10 - он как раз и соответствует ребру 1-4:</p>
80
<p>На рисунке цветом выделены все нулевые элементы. Рядом с каждым записан суммарный штраф. Максимальный штраф 10 - он как раз и соответствует ребру 1-4:</p>
81
<h3>Исключение ребра</h3>
81
<h3>Исключение ребра</h3>
82
<p>Спускаясь по левому поддереву, мы должны помнить, что ребро 1-4 в маршрут включать нельзя. Алгоритм Литтла предлагает хранить ее непосредственно в матрице смежности, поместив особое значение в первую строку четвертого столбца. Как и раньше, мы можем хранить очень большое число или константу Infinity.</p>
82
<p>Спускаясь по левому поддереву, мы должны помнить, что ребро 1-4 в маршрут включать нельзя. Алгоритм Литтла предлагает хранить ее непосредственно в матрице смежности, поместив особое значение в первую строку четвертого столбца. Как и раньше, мы можем хранить очень большое число или константу Infinity.</p>
83
<p>Рассмотрим новую матрицу для левого поддерева. Обратите внимание, что она может оказаться нередуцированной, как получилось в нашем случае. Редуцируем ее по первой строке четвертого столбца:</p>
83
<p>Рассмотрим новую матрицу для левого поддерева. Обратите внимание, что она может оказаться нередуцированной, как получилось в нашем случае. Редуцируем ее по первой строке четвертого столбца:</p>
84
<h3>Правое поддерево</h3>
84
<h3>Правое поддерево</h3>
85
<p>Если мы переместились по маршруту 1→4, мы больше не можем вернуться в город 1 и уехать в любой другой город. Так происходит, потому что коммивояжер может посетить каждый город только один раз.</p>
85
<p>Если мы переместились по маршруту 1→4, мы больше не можем вернуться в город 1 и уехать в любой другой город. Так происходит, потому что коммивояжер может посетить каждый город только один раз.</p>
86
<p>Это значит, что выбрав ребро 1-4, мы одновременно должны вычеркнуть первую строку четвертого столбца. Другими словами, нужно исключить из матрицы следующие ребра:</p>
86
<p>Это значит, что выбрав ребро 1-4, мы одновременно должны вычеркнуть первую строку четвертого столбца. Другими словами, нужно исключить из матрицы следующие ребра:</p>
87
<ul><li>1→2</li>
87
<ul><li>1→2</li>
88
<li>1→3</li>
88
<li>1→3</li>
89
<li>1→5</li>
89
<li>1→5</li>
90
<li>1→6</li>
90
<li>1→6</li>
91
<li>2→4</li>
91
<li>2→4</li>
92
<li>3→4</li>
92
<li>3→4</li>
93
<li>5→4</li>
93
<li>5→4</li>
94
<li>6→4</li>
94
<li>6→4</li>
95
</ul><p>Простой способ вычеркнуть строку и столбец - заполнить их значением ∞.</p>
95
</ul><p>Простой способ вычеркнуть строку и столбец - заполнить их значением ∞.</p>
96
<p>Кроме того, переехав по маршруту 1→4 мы не можем вернуться. Поэтому ребро 4-1 также можно исключить, записав в соответствующую ячейку значение ∞.</p>
96
<p>Кроме того, переехав по маршруту 1→4 мы не можем вернуться. Поэтому ребро 4-1 также можно исключить, записав в соответствующую ячейку значение ∞.</p>
97
<p>На рисунке показана матрица после этих преобразований:</p>
97
<p>На рисунке показана матрица после этих преобразований:</p>
98
<p>Ее можно редуцировать, вычтя минимумы из каждой строки и каждого столбца:</p>
98
<p>Ее можно редуцировать, вычтя минимумы из каждой строки и каждого столбца:</p>
99
<p>Посчитаем сумму минимумов:</p>
99
<p>Посчитаем сумму минимумов:</p>
100
<p>Эту сумму минимумов надо прибавить к предыдущей нижней границе. Так мы получим нижнюю границу правого поддерева 48+1=49:</p>
100
<p>Эту сумму минимумов надо прибавить к предыдущей нижней границе. Так мы получим нижнюю границу правого поддерева 48+1=49:</p>
101
<h3>Цикл</h3>
101
<h3>Цикл</h3>
102
<p>Таким образом, мы построили два поддерева. Пока у нас не хватает информации для отсечения, поэтому мы оставляем оба поддерева и выбираем одно из них для последующего ветвления. Разумно выбирать узел с наименьшей нижней границей. В нашем примере это правый узел, включающий ребро 1-4.</p>
102
<p>Таким образом, мы построили два поддерева. Пока у нас не хватает информации для отсечения, поэтому мы оставляем оба поддерева и выбираем одно из них для последующего ветвления. Разумно выбирать узел с наименьшей нижней границей. В нашем примере это правый узел, включающий ребро 1-4.</p>
103
<p>Берем матрицу правого поддерева. Она уже редуцирована, так что мы ищем нулевой элемент с максимальным штрафом:</p>
103
<p>Берем матрицу правого поддерева. Она уже редуцирована, так что мы ищем нулевой элемент с максимальным штрафом:</p>
104
<p>Максимальный штраф - 16, он соответствует ребру 2-1. Его мы и выберем для ветвления дерева. Как и на первом шаге, левое поддерево будет соответствовать маршрутам без ребра 2-1. В матрице левого поддерева достаточно записать ∞ во вторую строку первого столбца:</p>
104
<p>Максимальный штраф - 16, он соответствует ребру 2-1. Его мы и выберем для ветвления дерева. Как и на первом шаге, левое поддерево будет соответствовать маршрутам без ребра 2-1. В матрице левого поддерева достаточно записать ∞ во вторую строку первого столбца:</p>
105
<p>В правом поддереве мы вычеркиваем вторую строку первого столбца - заполняем их значением ∞.</p>
105
<p>В правом поддереве мы вычеркиваем вторую строку первого столбца - заполняем их значением ∞.</p>
106
<p>Также нам надо избавиться от обратного ребра 1-2. Но оно уже вычеркнуто из матрицы на предыдущем шаге, так что мы ничего дополнительно не делаем:</p>
106
<p>Также нам надо избавиться от обратного ребра 1-2. Но оно уже вычеркнуто из матрицы на предыдущем шаге, так что мы ничего дополнительно не делаем:</p>
107
<p>В алгоритме Литтла маршрут не строится последовательно, как это было в методе перебора. На каждом шаге мы выбираем ребро с максимальным штрафом. Два последовательно выбранных ребра могут даже не соединяться друг с другом.</p>
107
<p>В алгоритме Литтла маршрут не строится последовательно, как это было в методе перебора. На каждом шаге мы выбираем ребро с максимальным штрафом. Два последовательно выбранных ребра могут даже не соединяться друг с другом.</p>
108
<p>В нашем примере ребра 1-4 и 2-1 соединены через вершину 1. Добавим к ним ребро 4-2 и замкнем маршрут - правда, он будет пролегать не по всем шести городам, а только по трем.</p>
108
<p>В нашем примере ребра 1-4 и 2-1 соединены через вершину 1. Добавим к ним ребро 4-2 и замкнем маршрут - правда, он будет пролегать не по всем шести городам, а только по трем.</p>
109
<p>Это нарушает условие задачи коммивояжера, поэтому мы должны исключить ребро 4-2 из матрицы, поместив в ячейку ∞.</p>
109
<p>Это нарушает условие задачи коммивояжера, поэтому мы должны исключить ребро 4-2 из матрицы, поместив в ячейку ∞.</p>
110
<p>Делаем редукцию получившейся матрицы:</p>
110
<p>Делаем редукцию получившейся матрицы:</p>
111
<p>Нижняя граница для правого поддерева увеличивается на:</p>
111
<p>Нижняя граница для правого поддерева увеличивается на:</p>
112
<p>(2+0+0+0)+(0+0+0+0 )=2</p>
112
<p>(2+0+0+0)+(0+0+0+0 )=2</p>
113
<p>В итоге новая нижняя граница будет равна 49+2=51:</p>
113
<p>В итоге новая нижняя граница будет равна 49+2=51:</p>
114
<p>Сейчас у нас есть список вершин, доступных для ветвления. В нем находятся вершины с нижней границей 58, 65 и 51. Как и раньше, продолжим ветвление узла с наименьшей оценкой.</p>
114
<p>Сейчас у нас есть список вершин, доступных для ветвления. В нем находятся вершины с нижней границей 58, 65 и 51. Как и раньше, продолжим ветвление узла с наименьшей оценкой.</p>
115
<p>Выбираем ребро 5-6 с наибольшим штрафом (22):</p>
115
<p>Выбираем ребро 5-6 с наибольшим штрафом (22):</p>
116
<p>Продолжаем ветвление узла с наименьшей оценкой 56. Здесь максимальный штраф 8 соответствует ребрам 3-5 и 6-2. Для ветвления мы можем выбрать любое ребро, для примера пусть будет 3-5:</p>
116
<p>Продолжаем ветвление узла с наименьшей оценкой 56. Здесь максимальный штраф 8 соответствует ребрам 3-5 и 6-2. Для ветвления мы можем выбрать любое ребро, для примера пусть будет 3-5:</p>
117
<p>В самом правом поддереве можно образовать короткий маршрут из трех ребер:</p>
117
<p>В самом правом поддереве можно образовать короткий маршрут из трех ребер:</p>
118
<ul><li>3-5</li>
118
<ul><li>3-5</li>
119
<li>5-6</li>
119
<li>5-6</li>
120
<li>6-3</li>
120
<li>6-3</li>
121
</ul><p>Этот короткий цикл не является решением, поэтому вычеркиваем ребро 6-3 из матрицы.</p>
121
</ul><p>Этот короткий цикл не является решением, поэтому вычеркиваем ребро 6-3 из матрицы.</p>
122
<p>На этом этапе мы уже привыкли к тому, что продолжаем ветвление самого правого поддерева. Но сейчас нижняя граница длины маршрута в этом поддереве равна 63, хотя вверху слева у нас есть поддерево с оценкой 58.</p>
122
<p>На этом этапе мы уже привыкли к тому, что продолжаем ветвление самого правого поддерева. Но сейчас нижняя граница длины маршрута в этом поддереве равна 63, хотя вверху слева у нас есть поддерево с оценкой 58.</p>
123
<p>Возвращаемся к узлу, где вычеркнуто ребро 1-4. Разбиваем его на два поддерева:</p>
123
<p>Возвращаемся к узлу, где вычеркнуто ребро 1-4. Разбиваем его на два поддерева:</p>
124
<p>Среди всех ребер есть 6-3 с максимальным штрафом - 9. Таким образом:</p>
124
<p>Среди всех ребер есть 6-3 с максимальным штрафом - 9. Таким образом:</p>
125
<ul><li>Стоимость левого поддерева равна 58+9=67, если вычеркнуть ребро 6-3</li>
125
<ul><li>Стоимость левого поддерева равна 58+9=67, если вычеркнуть ребро 6-3</li>
126
<li>Стоимость правого поддерева равна 58+5=63, если вычеркнуть ячейку 3-6 и шестую строку третьего столбца</li>
126
<li>Стоимость правого поддерева равна 58+5=63, если вычеркнуть ячейку 3-6 и шестую строку третьего столбца</li>
127
</ul><p>На схеме это выглядит так:</p>
127
</ul><p>На схеме это выглядит так:</p>
128
<p>На этом этапе мы ни разу не проводили отсечение, потому что пока у нас нет ни одного построенного маршрута.</p>
128
<p>На этом этапе мы ни разу не проводили отсечение, потому что пока у нас нет ни одного построенного маршрута.</p>
129
<p>Сейчас в дереве решений есть два узла с минимальной нижней границей 63. Мы можем выбрать любое из них. Выберем самое правое поддерево и посмотрим на его матрицу:</p>
129
<p>Сейчас в дереве решений есть два узла с минимальной нижней границей 63. Мы можем выбрать любое из них. Выберем самое правое поддерево и посмотрим на его матрицу:</p>
130
<p>В этот момент мы останавливаемся, потому что у нас останется только два решения - два значения в матрице, которые меньше ∞.</p>
130
<p>В этот момент мы останавливаемся, потому что у нас останется только два решения - два значения в матрице, которые меньше ∞.</p>
131
<p>Фактически, сейчас у нас нет выбора - нам нужно найти два недостающие ребра и вставить их в маршрут в произвольном порядке. В нашем случае это ребра 4-3 и 6-2. Если бы в ячейках были ненулевые значения, то нам бы потребовалась редукция - в данном случае она не нужна.</p>
131
<p>Фактически, сейчас у нас нет выбора - нам нужно найти два недостающие ребра и вставить их в маршрут в произвольном порядке. В нашем случае это ребра 4-3 и 6-2. Если бы в ячейках были ненулевые значения, то нам бы потребовалась редукция - в данном случае она не нужна.</p>
132
<p>Нижняя граница длины маршрута в поддереве равна единственному маршруту в нем - а именно 63:</p>
132
<p>Нижняя граница длины маршрута в поддереве равна единственному маршруту в нем - а именно 63:</p>
133
<p>Итак, мы построили первый маршрут длиной 63. У нас есть недостроенные поддеревья с нижними границами 67, 63, 73 и 64. Нет ни одного поддерева с нижней границей меньше 63. Это значит, что в дереве решений точно нет маршрута, который мы уже нашли. Работу алгоритма можно завершить.</p>
133
<p>Итак, мы построили первый маршрут длиной 63. У нас есть недостроенные поддеревья с нижними границами 67, 63, 73 и 64. Нет ни одного поддерева с нижней границей меньше 63. Это значит, что в дереве решений точно нет маршрута, который мы уже нашли. Работу алгоритма можно завершить.</p>
134
<p>Если бы у нас оказалось несколько узлов с меньшей нижней границей, мы бы оставили только их, а остальные бы отсекли.</p>
134
<p>Если бы у нас оказалось несколько узлов с меньшей нижней границей, мы бы оставили только их, а остальные бы отсекли.</p>
135
<p>Самый короткий маршрут из найденных называется<strong>рекордным маршрутом</strong>или<strong>рекордом</strong>. На каждом шаге алгоритма мы можем отсекать поддеревья с нижней границей, которая больше или равна длине рекордного маршрута.</p>
135
<p>Самый короткий маршрут из найденных называется<strong>рекордным маршрутом</strong>или<strong>рекордом</strong>. На каждом шаге алгоритма мы можем отсекать поддеревья с нижней границей, которая больше или равна длине рекордного маршрута.</p>
136
<p>Мы последовательно достраиваем очередное поддерево до конца и получаем новый маршрут. При этом мы должны постоянно проверять, не короче ли новый маршрут текущего рекорда. Если короче, он сам должен стать новым рекордным маршрутом.</p>
136
<p>Мы последовательно достраиваем очередное поддерево до конца и получаем новый маршрут. При этом мы должны постоянно проверять, не короче ли новый маршрут текущего рекорда. Если короче, он сам должен стать новым рекордным маршрутом.</p>
137
<h2>Выводы</h2>
137
<h2>Выводы</h2>
138
<p>В этом уроке мы познакомились с алгоритмом Литтла. Повторим ключевые выводы:</p>
138
<p>В этом уроке мы познакомились с алгоритмом Литтла. Повторим ключевые выводы:</p>
139
<ul><li>Алгоритм Литтла находит оптимальное решение в дереве решений</li>
139
<ul><li>Алгоритм Литтла находит оптимальное решение в дереве решений</li>
140
<li>Для работы алгоритма важно, чтобы оценка нижней границы была корректной</li>
140
<li>Для работы алгоритма важно, чтобы оценка нижней границы была корректной</li>
141
<li>Обычно алгоритм Литтла работает быстрее метода перебора, в худшем случае - с той же скоростью O(n!)</li>
141
<li>Обычно алгоритм Литтла работает быстрее метода перебора, в худшем случае - с той же скоростью O(n!)</li>
142
</ul><p>Пока наше знакомство ограничилось только теорией, но уже в следующем уроке мы разберем, как реализовать алгоритм Литтла на практике.</p>
142
</ul><p>Пока наше знакомство ограничилось только теорией, но уже в следующем уроке мы разберем, как реализовать алгоритм Литтла на практике.</p>