1 added
1 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>В этом уроке рассмотрим задачи о командировке и времени выполнения алгоритмов, чтобы посмотреть, как работать с гамильтоновыми циклами и NP-полнотой.</p>
1
<p>В этом уроке рассмотрим задачи о командировке и времени выполнения алгоритмов, чтобы посмотреть, как работать с гамильтоновыми циклами и NP-полнотой.</p>
2
<h2>Задача с маршрутом командировки</h2>
2
<h2>Задача с маршрутом командировки</h2>
3
<p>Представим, что сотруднику нужно посетить несколько городов подряд и вернуться домой. Эта командировка из одного города в другой связано с различными расходами, поэтому компания хочет заказать самую дешевую поездку, которая охватывает все города.</p>
3
<p>Представим, что сотруднику нужно посетить несколько городов подряд и вернуться домой. Эта командировка из одного города в другой связано с различными расходами, поэтому компания хочет заказать самую дешевую поездку, которая охватывает все города.</p>
4
<p>В графовой задаче города - это вершины, ребро между вершинами указывает на возможность прямого проезда между двумя городами, а веса на ребрах - стоимость поездки между двумя соответствующими городами.</p>
4
<p>В графовой задаче города - это вершины, ребро между вершинами указывает на возможность прямого проезда между двумя городами, а веса на ребрах - стоимость поездки между двумя соответствующими городами.</p>
5
<p>Нам нужно найти гамильтонов цикл с минимальным весом. Например, ниже показан граф с выделенным оптимальным решением:</p>
5
<p>Нам нужно найти гамильтонов цикл с минимальным весом. Например, ниже показан граф с выделенным оптимальным решением:</p>
6
<p>Если проверять все возможные маршруты, то это только усложнит решение задачи. Если каждый город соединен с другим, то существует n! возможных маршрутов.</p>
6
<p>Если проверять все возможные маршруты, то это только усложнит решение задачи. Если каждый город соединен с другим, то существует n! возможных маршрутов.</p>
7
<p>Можно упростить решение с помощью динамического программирования. Это позволит сократить количество проверяемых маршрутов до (n^2)(2^n), что является значительным улучшением, но все равно является экспоненциальным.</p>
7
<p>Можно упростить решение с помощью динамического программирования. Это позволит сократить количество проверяемых маршрутов до (n^2)(2^n), что является значительным улучшением, но все равно является экспоненциальным.</p>
8
<p>На примере этой задачи мы видим, как математики находят такие алгоритмы, которые работают даже на больших масштабах - например, для карт, состоящих из многих тысяч городов.</p>
8
<p>На примере этой задачи мы видим, как математики находят такие алгоритмы, которые работают даже на больших масштабах - например, для карт, состоящих из многих тысяч городов.</p>
9
<h2>Задача с временем выполнения</h2>
9
<h2>Задача с временем выполнения</h2>
10
<p>До сих пор мы рассмотрели несколько алгоритмов работы с графами. Один из самых важных аспектов - скорость их работы. Например, есть алгоритмы, время выполнения которых меняется, если мы меняем количество вершин или ребер в графе. На это указывает<strong>NP-полнота</strong>- класс сложности. Пока мы не будем углубляться в эту сложную тему, но измерим время работы алгоритмов.</p>
10
<p>До сих пор мы рассмотрели несколько алгоритмов работы с графами. Один из самых важных аспектов - скорость их работы. Например, есть алгоритмы, время выполнения которых меняется, если мы меняем количество вершин или ребер в графе. На это указывает<strong>NP-полнота</strong>- класс сложности. Пока мы не будем углубляться в эту сложную тему, но измерим время работы алгоритмов.</p>
11
<p>Предположим, у нас есть следующий код на языке Python, который суммирует все значения в списке:</p>
11
<p>Предположим, у нас есть следующий код на языке Python, который суммирует все значения в списке:</p>
12
<p>Допустим, список состоит из n элементов. Код рассматривает каждый элемент и тратит определенное время на то, чтобы добавить его значение в общую сумму. Также определенное время требуется для выполнения других мелких действий, например, установки общего значения в 0.</p>
12
<p>Допустим, список состоит из n элементов. Код рассматривает каждый элемент и тратит определенное время на то, чтобы добавить его значение в общую сумму. Также определенное время требуется для выполнения других мелких действий, например, установки общего значения в 0.</p>
13
<p>Получается, время работы этого алгоритма на конкретном компьютере может составлять 2,3n + 0.2 микросекунды. Константы 2,3 и 0.2 будут варьироваться от компьютера к компьютеру. Нас интересует n. Обычно это записывается как O(n), что читается как "большое O из n". Это говорит нам о порядке роста времени выполнения.</p>
13
<p>Получается, время работы этого алгоритма на конкретном компьютере может составлять 2,3n + 0.2 микросекунды. Константы 2,3 и 0.2 будут варьироваться от компьютера к компьютеру. Нас интересует n. Обычно это записывается как O(n), что читается как "большое O из n". Это говорит нам о порядке роста времени выполнения.</p>
14
<p>Так как порядок роста равен O(n) - это линейный алгоритм. Получается, если мы удвоим количество элементов в списке, время работы увеличится примерно вдвое. Если мы утроим количество элементов, время работы увеличится примерно втрое.</p>
14
<p>Так как порядок роста равен O(n) - это линейный алгоритм. Получается, если мы удвоим количество элементов в списке, время работы увеличится примерно вдвое. Если мы утроим количество элементов, время работы увеличится примерно втрое.</p>
15
<p>В качестве другого примера предположим, что мы хотим сложить элементы в матрице n * n. В этом случае время работы может составить 3,4n^2 + 0.2. Мы бы записали это как O(n^2). Это говорит, что время работы растет как квадрат n. Это квадратичный алгоритм:</p>
15
<p>В качестве другого примера предположим, что мы хотим сложить элементы в матрице n * n. В этом случае время работы может составить 3,4n^2 + 0.2. Мы бы записали это как O(n^2). Это говорит, что время работы растет как квадрат n. Это квадратичный алгоритм:</p>
16
<ul><li>Если мы удвоим количество записей, то время работы увеличится примерно в четыре раза</li>
16
<ul><li>Если мы удвоим количество записей, то время работы увеличится примерно в четыре раза</li>
17
<li>Если мы утроим количество записей, то время работы увеличится примерно в девять раз</li>
17
<li>Если мы утроим количество записей, то время работы увеличится примерно в девять раз</li>
18
</ul><p>Оба примера показывают полиномиальный рост. Это значит, что у алгоритма есть входные данные, у которых есть размер. Например, у алгоритма сортировки массива размером считается количество элементов в массиве. Если для любого входа количество операций при выполнении алгоритма не больше какого-то полинома от размера входа, то это полиномиальный алгоритм.</p>
18
</ul><p>Оба примера показывают полиномиальный рост. Это значит, что у алгоритма есть входные данные, у которых есть размер. Например, у алгоритма сортировки массива размером считается количество элементов в массиве. Если для любого входа количество операций при выполнении алгоритма не больше какого-то полинома от размера входа, то это полиномиальный алгоритм.</p>
19
<p>Любой алгоритм, время работы которого является полиномом, называется<strong>алгоритмом полиномиального времени</strong>. Для обозначения совокупности всех алгоритмов, выполняющихся за полиномиальное время, используется заглавная буква P.</p>
19
<p>Любой алгоритм, время работы которого является полиномом, называется<strong>алгоритмом полиномиального времени</strong>. Для обозначения совокупности всех алгоритмов, выполняющихся за полиномиальное время, используется заглавная буква P.</p>
20
<p>Не все алгоритмы выполняются за полиномиальное время. Например, если перечислить все подмножества из {1, 2, . . . , n}, это был бы алгоритм O(2^n), поскольку существует 2^n подмножеств. Это пример экспоненциального алгоритма. Здесь простое добавление еще одного элемента к множеству удваивает время работы.</p>
20
<p>Не все алгоритмы выполняются за полиномиальное время. Например, если перечислить все подмножества из {1, 2, . . . , n}, это был бы алгоритм O(2^n), поскольку существует 2^n подмножеств. Это пример экспоненциального алгоритма. Здесь простое добавление еще одного элемента к множеству удваивает время работы.</p>
21
<p>Алгоритмы с полиномиальным временем обычно предпочтительнее алгоритмов с экспоненциальным временем. Чтобы понять почему, рассмотрим огромную разницу в росте между n^2 и 2^n:</p>
21
<p>Алгоритмы с полиномиальным временем обычно предпочтительнее алгоритмов с экспоненциальным временем. Чтобы понять почему, рассмотрим огромную разницу в росте между n^2 и 2^n:</p>
22
<p>10^2 = 100 2^10 = 1024</p>
22
<p>10^2 = 100 2^10 = 1024</p>
23
<p>100^2 = 10000 2^100 = 1.27 * 10^30</p>
23
<p>100^2 = 10000 2^100 = 1.27 * 10^30</p>
24
<p>1000^2 = 1000000 2^1000 = 1.07 * 10^301</p>
24
<p>1000^2 = 1000000 2^1000 = 1.07 * 10^301</p>
25
<p>Предположим, что нам нужно выбрать один из двух алгоритмов, чтобы поработать с двумя графами:</p>
25
<p>Предположим, что нам нужно выбрать один из двух алгоритмов, чтобы поработать с двумя графами:</p>
26
<ul><li>Первый граф O(n^2)</li>
26
<ul><li>Первый граф O(n^2)</li>
27
<li>Второй граф O(2^n)</li>
27
<li>Второй граф O(2^n)</li>
28
</ul><p>На графе с 1000 вершинами у алгоритма O(n^2) будет время работы примерно 1 000 000 единиц времени. Если эти единицы времени - микросекунды, то на выполнение алгоритма уйдет около секунды. С другой стороны, алгоритм O(2^n) занимает 1,07 * 10^301 единицу времени, что намного больше, чем возраст Вселенной - это число с 301 нулем. С практической точки зрения, экспоненциальный алгоритм непригоден для использования.</p>
28
</ul><p>На графе с 1000 вершинами у алгоритма O(n^2) будет время работы примерно 1 000 000 единиц времени. Если эти единицы времени - микросекунды, то на выполнение алгоритма уйдет около секунды. С другой стороны, алгоритм O(2^n) занимает 1,07 * 10^301 единицу времени, что намного больше, чем возраст Вселенной - это число с 301 нулем. С практической точки зрения, экспоненциальный алгоритм непригоден для использования.</p>
29
<p>Экспоненциальные алгоритмы иногда могут превосходить полиномиальные, если число вершин относительно невелико. Здесь мы опустим детали. Когда число вершин становится достаточно большим, экспоненциальные алгоритмы оказываются намного хуже полиномиальных.</p>
29
<p>Экспоненциальные алгоритмы иногда могут превосходить полиномиальные, если число вершин относительно невелико. Здесь мы опустим детали. Когда число вершин становится достаточно большим, экспоненциальные алгоритмы оказываются намного хуже полиномиальных.</p>
30
<h3>NP-полные проблемы</h3>
30
<h3>NP-полные проблемы</h3>
31
<p>Существует еще одна группа задач с NP-полнотой, где требуется полиномиальное количество времени:</p>
31
<p>Существует еще одна группа задач с NP-полнотой, где требуется полиномиальное количество времени:</p>
32
<p>Все, что находится в P, также находится в NP, но NP содержит некоторые другие проблемы, которых нет в P</p>
32
<p>Все, что находится в P, также находится в NP, но NP содержит некоторые другие проблемы, которых нет в P</p>
33
<p>Наглядный пример такой задачи - судоку. Если у нас есть решение судоку, несложно проверить, что оно работает. Для этого нужно просмотреть каждую строку, столбец и блок - и убедиться, что нет повторений. При этом решение судоку гораздо сложнее. Никто не знает полиномиального алгоритма, который бы находил решения для n * n судоку.</p>
33
<p>Наглядный пример такой задачи - судоку. Если у нас есть решение судоку, несложно проверить, что оно работает. Для этого нужно просмотреть каждую строку, столбец и блок - и убедиться, что нет повторений. При этом решение судоку гораздо сложнее. Никто не знает полиномиального алгоритма, который бы находил решения для n * n судоку.</p>
34
<p>Разберем еще один похожий пример: проблему суммы подмножеств. Нам нужно понять, можно ли найти подмножество набора целых чисел, сумма элементов которого равна 0.</p>
34
<p>Разберем еще один похожий пример: проблему суммы подмножеств. Нам нужно понять, можно ли найти подмножество набора целых чисел, сумма элементов которого равна 0.</p>
35
<p>Например, задано такое множество {-20,-12,-10,-7,-3, 4, 5, 9, 18, 25}. Чтобы найти подмножество, сумма элементов которого равна 0, потребуется некоторое время. При этом можно проверить, что {-12,-10, 4, 18} работает - на это требуется очень мало времени.</p>
35
<p>Например, задано такое множество {-20,-12,-10,-7,-3, 4, 5, 9, 18, 25}. Чтобы найти подмножество, сумма элементов которого равна 0, потребуется некоторое время. При этом можно проверить, что {-12,-10, 4, 18} работает - на это требуется очень мало времени.</p>
36
<p>Но чтобы найти решение для множества с тысячами элементов, потребуется огромное количество времени. При этом нужно намного меньше времени, чтобы сложить элементы потенциального решения и проверить его работоспособность.</p>
36
<p>Но чтобы найти решение для множества с тысячами элементов, потребуется огромное количество времени. При этом нужно намного меньше времени, чтобы сложить элементы потенциального решения и проверить его работоспособность.</p>
37
<p>Судоку и проблема суммы подмножеств называются<strong>NP-полными проблемами</strong>. Если кто-то найдет решение NP-полной задачи за полиномиальное время, то он сможет решать любые другие NP-полные задачи за полиномиальное время. До сих пор никто не нашел такого решения, а имеющиеся способы имеют экспоненциальное время.</p>
37
<p>Судоку и проблема суммы подмножеств называются<strong>NP-полными проблемами</strong>. Если кто-то найдет решение NP-полной задачи за полиномиальное время, то он сможет решать любые другие NP-полные задачи за полиномиальное время. До сих пор никто не нашел такого решения, а имеющиеся способы имеют экспоненциальное время.</p>
38
<h2>Проблема P=NP</h2>
38
<h2>Проблема P=NP</h2>
39
<p>В математике существует одна из самых важных проблем -<strong>проблемой P=NP</strong>. То есть никто не знает, равны ли между собой P и NP. Если мы можем проверить правильность решения, значит ли это, что мы можем решить такую проблему? Не совсем. За решение этой проблемы полагается приз в миллион долларов. Большинство математиков и компьютерных ученых считают, что P не равна NP, но не все с этим согласны. Правда пока никто не приблизился к решению проблемы.</p>
39
<p>В математике существует одна из самых важных проблем -<strong>проблемой P=NP</strong>. То есть никто не знает, равны ли между собой P и NP. Если мы можем проверить правильность решения, значит ли это, что мы можем решить такую проблему? Не совсем. За решение этой проблемы полагается приз в миллион долларов. Большинство математиков и компьютерных ученых считают, что P не равна NP, но не все с этим согласны. Правда пока никто не приблизился к решению проблемы.</p>
40
-
<p>Некоторые из проблем, которые мы рассматривали в теории графов, относятся к P. К ним относятся эйлеровы цепи схемы, кратчайшие пути в графах и минимальные прямые деревья. Другие проблемы, которые мы видели, являются NP-полными: гамильтоновы циклы, длиннейшие пути в графах и нахождение максимальных независимых множеств.</p>
40
+
<p>Некоторые из проблем, которые мы рассматривали в теории графов, относятся к P. К ним относятся эйлеровы цепи схемы, кратчайшие пути в графах и минимальные остовные деревья. Другие проблемы, которые мы видели, являются NP-полными: гамильтоновы циклы, длиннейшие пути в графах и нахождение максимальных независимых множеств.</p>
41
<p>Если проблема эйлеровой цепи находится в P, значит, существует полиномиальный алгоритм, который определяет, имеет ли граф эйлерову цепь или нет. Перебор и проверка степеней каждой вершины, чтобы узнать, все ли они четные, - это полиномиальный алгоритм.<strong>Алгоритм Гирхольцера</strong>и<strong>алгоритм Флери</strong>для нахождения таких схем также являются полиномиальными алгоритмами.</p>
41
<p>Если проблема эйлеровой цепи находится в P, значит, существует полиномиальный алгоритм, который определяет, имеет ли граф эйлерову цепь или нет. Перебор и проверка степеней каждой вершины, чтобы узнать, все ли они четные, - это полиномиальный алгоритм.<strong>Алгоритм Гирхольцера</strong>и<strong>алгоритм Флери</strong>для нахождения таких схем также являются полиномиальными алгоритмами.</p>
42
<p>Проблема гамильтонова цикла является NP-полной, так как если кто-то дает нам гамильтонов цикл в графе, то легко проверить, что это действительно гамильтонов цикл. Однако люди доказали, что полиномиальное решение проблемы гамильтонова цикла даст полиномиальное решение любой другой проблемы в NP.</p>
42
<p>Проблема гамильтонова цикла является NP-полной, так как если кто-то дает нам гамильтонов цикл в графе, то легко проверить, что это действительно гамильтонов цикл. Однако люди доказали, что полиномиальное решение проблемы гамильтонова цикла даст полиномиальное решение любой другой проблемы в NP.</p>
43
<p>Получается,<strong>проблема гамильтонова цикла</strong>- NP-полная. Никто не нашел решения проблемы гамильтонова цикла за полиномиальное время, и очень вероятно, что никто и никогда не найдет.</p>
43
<p>Получается,<strong>проблема гамильтонова цикла</strong>- NP-полная. Никто не нашел решения проблемы гамильтонова цикла за полиномиальное время, и очень вероятно, что никто и никогда не найдет.</p>
44
<p><strong>Алгоритм Дейкстры</strong>для кратчайших путей тоже работает за полиномиальное время. С другой стороны, поиск самого длинного пути в графе является NP-полной задачей. Единственные известные алгоритмы работают в экспоненциальном времени, поэтому поиск самого длинного пути в графе может занять много времени, особенно для больших графов.</p>
44
<p><strong>Алгоритм Дейкстры</strong>для кратчайших путей тоже работает за полиномиальное время. С другой стороны, поиск самого длинного пути в графе является NP-полной задачей. Единственные известные алгоритмы работают в экспоненциальном времени, поэтому поиск самого длинного пути в графе может занять много времени, особенно для больших графов.</p>
45
<p>Если проблема с графом оказывается в P, то, скорее всего, существует алгоритм, который решает эту проблему довольно быстро, даже для относительно больших графов. С другой стороны, если она NP-полная, то решение проблемы для произвольных больших графов, скорее всего, будет трудным и займет неуправляемое количество времени.</p>
45
<p>Если проблема с графом оказывается в P, то, скорее всего, существует алгоритм, который решает эту проблему довольно быстро, даже для относительно больших графов. С другой стороны, если она NP-полная, то решение проблемы для произвольных больших графов, скорее всего, будет трудным и займет неуправляемое количество времени.</p>
46
<p>Еще пример: поиск максимальных независимых множеств является NP-полной проблемой, но если мы просто хотим найти максимальные независимые множества на деревьях, то это является управляемой полиномиально-временной проблемой.</p>
46
<p>Еще пример: поиск максимальных независимых множеств является NP-полной проблемой, но если мы просто хотим найти максимальные независимые множества на деревьях, то это является управляемой полиномиально-временной проблемой.</p>
47
<h2>Выводы</h2>
47
<h2>Выводы</h2>
48
<p>Иногда проблему можно решить на определенных классах графов. Например, нахождение гамильтоновых циклов является NP-полной задачей, что означает, что мы не можем рассчитывать на хороший алгоритм, работающий для любого графа. Но если мы ограничимся только полными графами, то проблема будет простой.</p>
48
<p>Иногда проблему можно решить на определенных классах графов. Например, нахождение гамильтоновых циклов является NP-полной задачей, что означает, что мы не можем рассчитывать на хороший алгоритм, работающий для любого графа. Но если мы ограничимся только полными графами, то проблема будет простой.</p>