HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-21
1 <p><a>#статьи</a></p>
1 <p><a>#статьи</a></p>
2 <ul><li>20 ноя 2023</li>
2 <ul><li>20 ноя 2023</li>
3 <li>0</li>
3 <li>0</li>
4 </ul><h2>Алгоритм Дейкстры: что это такое, как работает и где используется</h2>
4 </ul><h2>Алгоритм Дейкстры: что это такое, как работает и где используется</h2>
5 <p>С его помощью строят маршруты навигаторы, роботы и персонажи компьютерных игр.</p>
5 <p>С его помощью строят маршруты навигаторы, роботы и персонажи компьютерных игр.</p>
6 <p>Иллюстрация: Оля Ежак для Skillbox Media</p>
6 <p>Иллюстрация: Оля Ежак для Skillbox Media</p>
7 <p>Программист, консультант, специалист по документированию. Легко и доступно рассказывает о сложных вещах в программировании и дизайне.</p>
7 <p>Программист, консультант, специалист по документированию. Легко и доступно рассказывает о сложных вещах в программировании и дизайне.</p>
8 <p>Все мы пользуемся приложениями-навигаторами - вводим начальную и конечную точки, а программа строит самый оптимальный, на её взгляд, маршрут. Для этого она использует так называемые алгоритмы поиска кратчайшего пути. Сегодня поговорим о самых популярных из них - алгоритмах Дейкстры и А*. Выясним, как они работают, где применяются и чем отличаются друг от друга.</p>
8 <p>Все мы пользуемся приложениями-навигаторами - вводим начальную и конечную точки, а программа строит самый оптимальный, на её взгляд, маршрут. Для этого она использует так называемые алгоритмы поиска кратчайшего пути. Сегодня поговорим о самых популярных из них - алгоритмах Дейкстры и А*. Выясним, как они работают, где применяются и чем отличаются друг от друга.</p>
9 <p>Алгоритм Дейкстры - это метод нахождения кратчайших путей от одной вершины графа ко всем остальным.</p>
9 <p>Алгоритм Дейкстры - это метод нахождения кратчайших путей от одной вершины графа ко всем остальным.</p>
10 <p><strong>Граф</strong> - это математическая структура, которая состоит из вершин (узлов) и рёбер (связей) между ними. Рёбра могут иметь направление, а также веса - числа, которые обозначают силу связей с вершинами.</p>
10 <p><strong>Граф</strong> - это математическая структура, которая состоит из вершин (узлов) и рёбер (связей) между ними. Рёбра могут иметь направление, а также веса - числа, которые обозначают силу связей с вершинами.</p>
11 <p>Графы используются для представления объектов, их взаимосвязей и отношений между ними. Например, в виде графа можно представить социальную сеть, где вершины - это пользователи, дружеские связи между ними - рёбра, а веса - это, скажем, частота обмена сообщениями.</p>
11 <p>Графы используются для представления объектов, их взаимосвязей и отношений между ними. Например, в виде графа можно представить социальную сеть, где вершины - это пользователи, дружеские связи между ними - рёбра, а веса - это, скажем, частота обмена сообщениями.</p>
12 <em>Инфографика: Майя Мальгина для Skillbox Media</em><p>Но, конечно, одними социальными сетями прикладной смысл графов не ограничивается. Например, с их помощью можно моделировать связи между:</p>
12 <em>Инфографика: Майя Мальгина для Skillbox Media</em><p>Но, конечно, одними социальными сетями прикладной смысл графов не ограничивается. Например, с их помощью можно моделировать связи между:</p>
13 <ul><li>веб-страницами;</li>
13 <ul><li>веб-страницами;</li>
14 <li>улицами и перекрёстками при проектировании дорожной сети;</li>
14 <li>улицами и перекрёстками при проектировании дорожной сети;</li>
15 <li>генами, белками и молекулами в биоинформатике;</li>
15 <li>генами, белками и молекулами в биоинформатике;</li>
16 <li>пунктами доставки грузов в логистике;</li>
16 <li>пунктами доставки грузов в логистике;</li>
17 <li>точками передвижения роботов в робототехнике.</li>
17 <li>точками передвижения роботов в робототехнике.</li>
18 </ul><p>Идея алгоритма Дейкстры в том, что мы можем найти наименьшие расстояния от начальной вершины графа ко всем остальным. Зная эти расстояния, можно построить кратчайший маршрут между начальной и другими точками.</p>
18 </ul><p>Идея алгоритма Дейкстры в том, что мы можем найти наименьшие расстояния от начальной вершины графа ко всем остальным. Зная эти расстояния, можно построить кратчайший маршрут между начальной и другими точками.</p>
19 <p>Допустим, у нас есть несколько городов, соединённых дорогами. Назовём их <strong>А</strong>,<strong>B</strong>,<strong>C</strong>,<strong>D</strong>,<strong>E</strong>,<strong>F</strong>. Числа возле рёбер - расстояния между городами в милях.</p>
19 <p>Допустим, у нас есть несколько городов, соединённых дорогами. Назовём их <strong>А</strong>,<strong>B</strong>,<strong>C</strong>,<strong>D</strong>,<strong>E</strong>,<strong>F</strong>. Числа возле рёбер - расстояния между городами в милях.</p>
20 <em>Инфографика: Майя Мальгина для Skillbox Media</em><p>Теперь попробуем найти кратчайший маршрут, скажем, от A до C. Как это сделать? Вроде бы несложно: сравниваем все возможные пути и выбираем самый короткий:<strong>A → B → C</strong>. Банальный перебор, совсем не rocket science.</p>
20 <em>Инфографика: Майя Мальгина для Skillbox Media</em><p>Теперь попробуем найти кратчайший маршрут, скажем, от A до C. Как это сделать? Вроде бы несложно: сравниваем все возможные пути и выбираем самый короткий:<strong>A → B → C</strong>. Банальный перебор, совсем не rocket science.</p>
21 <p>Сложности начинаются, когда данных становится слишком много. Если бы городов на нашей карте было больше 26, даже самому мощному компьютеру<a>понадобилось бы</a>несколько миллиардов лет, чтобы просчитать все варианты.</p>
21 <p>Сложности начинаются, когда данных становится слишком много. Если бы городов на нашей карте было больше 26, даже самому мощному компьютеру<a>понадобилось бы</a>несколько миллиардов лет, чтобы просчитать все варианты.</p>
22 <p>Алгоритм Дейкстры работает иначе: он не перебирает "в уме" все возможные варианты, а строит маршрут пошагово. На каждом шаге алгоритм выбирает наименее отдалённую вершину и двигается к ней, затем к следующей - и так, пока не доберётся до цели.</p>
22 <p>Алгоритм Дейкстры работает иначе: он не перебирает "в уме" все возможные варианты, а строит маршрут пошагово. На каждом шаге алгоритм выбирает наименее отдалённую вершину и двигается к ней, затем к следующей - и так, пока не доберётся до цели.</p>
23 <p>Ключевой смысл такой: если на каждом этапе принимать оптимальные решения, то и конечное решение, скорее всего, тоже окажется оптимальным. Алгоритмы которые работают по такому принципу, называются жадными.</p>
23 <p>Ключевой смысл такой: если на каждом этапе принимать оптимальные решения, то и конечное решение, скорее всего, тоже окажется оптимальным. Алгоритмы которые работают по такому принципу, называются жадными.</p>
24 <p>Вернёмся к нашему графу с городами. Найдём с помощью алгоритма Дейкстры кратчайшие расстояния от <strong>А </strong>до<strong>B</strong>,<strong>C</strong>,<strong>D</strong>,<strong>E </strong>и<strong>F</strong>.</p>
24 <p>Вернёмся к нашему графу с городами. Найдём с помощью алгоритма Дейкстры кратчайшие расстояния от <strong>А </strong>до<strong>B</strong>,<strong>C</strong>,<strong>D</strong>,<strong>E </strong>и<strong>F</strong>.</p>
25 <p><strong>Шаг 1.</strong>Установим для каждой вершины первоначальную оценку пути до <strong>А</strong>. Для самой<strong>А</strong> оценка равна<strong>0</strong>, остальным присвоим бесконечность, так как мы пока не знаем их значения.</p>
25 <p><strong>Шаг 1.</strong>Установим для каждой вершины первоначальную оценку пути до <strong>А</strong>. Для самой<strong>А</strong> оценка равна<strong>0</strong>, остальным присвоим бесконечность, так как мы пока не знаем их значения.</p>
26 <em>Инфографика: Майя Мальгина для Skillbox Media</em><p>Рассмотрим соседние с <strong>A</strong>вершины - то есть те, которые связаны с <strong>А</strong>рёбрами напрямую. Это<strong>B</strong>и<strong>E </strong>-<strong></strong>их расстояния до <strong>А</strong>равны<strong>7</strong>и <strong>4</strong>соответственно. Так как эти значения, очевидно, меньше бесконечности, обновим их на схеме. Вершину<strong>А</strong>будем считать посещённой - закрасим её и больше не рассматриваем.</p>
26 <em>Инфографика: Майя Мальгина для Skillbox Media</em><p>Рассмотрим соседние с <strong>A</strong>вершины - то есть те, которые связаны с <strong>А</strong>рёбрами напрямую. Это<strong>B</strong>и<strong>E </strong>-<strong></strong>их расстояния до <strong>А</strong>равны<strong>7</strong>и <strong>4</strong>соответственно. Так как эти значения, очевидно, меньше бесконечности, обновим их на схеме. Вершину<strong>А</strong>будем считать посещённой - закрасим её и больше не рассматриваем.</p>
27 <em>Инфографика: Майя Мальгина для Skillbox Media</em><p>Теперь перейдём к непосещённой вершине с наименьшим расстоянием до <strong>А</strong>. Это вершина<strong>E</strong>. Соседние с ней непосещённые вершины -<strong>F</strong>и <strong>D</strong>. Их расстояния до <strong>А</strong>будут равны оценке<strong>E</strong>(то есть расстоянию от <strong>E </strong>до <strong>А</strong>) плюс веса рёбер от <strong>E</strong>до этих вершин. Получается так:</p>
27 <em>Инфографика: Майя Мальгина для Skillbox Media</em><p>Теперь перейдём к непосещённой вершине с наименьшим расстоянием до <strong>А</strong>. Это вершина<strong>E</strong>. Соседние с ней непосещённые вершины -<strong>F</strong>и <strong>D</strong>. Их расстояния до <strong>А</strong>будут равны оценке<strong>E</strong>(то есть расстоянию от <strong>E </strong>до <strong>А</strong>) плюс веса рёбер от <strong>E</strong>до этих вершин. Получается так:</p>
28 <ul><li>Для<strong>F</strong>: 4 + 3 = 7</li>
28 <ul><li>Для<strong>F</strong>: 4 + 3 = 7</li>
29 <li>Для<strong>D</strong>: 4 + 8 = 12</li>
29 <li>Для<strong>D</strong>: 4 + 8 = 12</li>
30 </ul><p>Полученные расстояния меньше предыдущих оценок, поэтому запишем их возле вершин<strong>F</strong>и<strong>D</strong>. Вершину<strong>E</strong>будем считать посещённой. Закрасим её.</p>
30 </ul><p>Полученные расстояния меньше предыдущих оценок, поэтому запишем их возле вершин<strong>F</strong>и<strong>D</strong>. Вершину<strong>E</strong>будем считать посещённой. Закрасим её.</p>
31 <em>Инфографика: Майя Мальгина для Skillbox Media</em><p>Дальше по аналогии: алгоритм выбирает непосещённые вершины с наименьшей оценкой и считает расстояния от соседних с ней вершин до <strong>А</strong>. И продолжается это до тех пор, пока алгоритм не вычислит кратчайшие расстояния до <strong>А</strong>для всех вершин.</p>
31 <em>Инфографика: Майя Мальгина для Skillbox Media</em><p>Дальше по аналогии: алгоритм выбирает непосещённые вершины с наименьшей оценкой и считает расстояния от соседних с ней вершин до <strong>А</strong>. И продолжается это до тех пор, пока алгоритм не вычислит кратчайшие расстояния до <strong>А</strong>для всех вершин.</p>
32 <em>Инфографика: Майя Мальгина для Skillbox Media</em><p>Готово! Теперь мы можем построить кратчайший маршрут от <strong>А</strong>до любой другой вершины. Например:</p>
32 <em>Инфографика: Майя Мальгина для Skillbox Media</em><p>Готово! Теперь мы можем построить кратчайший маршрут от <strong>А</strong>до любой другой вершины. Например:</p>
33 <ul><li>От <strong>A</strong>до <strong>F</strong>:<strong>A - E - F</strong></li>
33 <ul><li>От <strong>A</strong>до <strong>F</strong>:<strong>A - E - F</strong></li>
34 <li>От <strong>A </strong>до<strong>D: A - E - D</strong></li>
34 <li>От <strong>A </strong>до<strong>D: A - E - D</strong></li>
35 <li>От <strong>A </strong>до <strong>C: A - B - C</strong></li>
35 <li>От <strong>A </strong>до <strong>C: A - B - C</strong></li>
36 </ul><p>Но у алгоритма Дейкстры есть и ограничения: во-первых, он работает только со <strong>взвешенными</strong>графами - то есть такими, где веса между рёбрами известны заранее. А во-вторых, эти расстояния должны быть неотрицательными.</p>
36 </ul><p>Но у алгоритма Дейкстры есть и ограничения: во-первых, он работает только со <strong>взвешенными</strong>графами - то есть такими, где веса между рёбрами известны заранее. А во-вторых, эти расстояния должны быть неотрицательными.</p>
37 <p>Алгоритм поиска кратчайшего пути разработал голландский учёный Эдсгер Дейкстра в 1956 году. В то время он искал способ продемонстрировать возможности нового компьютера ARMAC и искал задачу, которую мог бы решить ARMAC и при этом понятную незнакомым с компьютерами людям.</p>
37 <p>Алгоритм поиска кратчайшего пути разработал голландский учёный Эдсгер Дейкстра в 1956 году. В то время он искал способ продемонстрировать возможности нового компьютера ARMAC и искал задачу, которую мог бы решить ARMAC и при этом понятную незнакомым с компьютерами людям.</p>
38 <p>Дейкстра взял задачу поиска кратчайшего пути и разработал алгоритм её решения. На базе алгоритма он разработал программу построения маршрутов между городами по транспортной карте Нидерландов.</p>
38 <p>Дейкстра взял задачу поиска кратчайшего пути и разработал алгоритм её решения. На базе алгоритма он разработал программу построения маршрутов между городами по транспортной карте Нидерландов.</p>
39 <p>Позже Дейкстра рассказывал:</p>
39 <p>Позже Дейкстра рассказывал:</p>
40 <p>"Однажды мы с моей невестой пили кофе на террасе кафе в Амстердаме. Там я примерно за двадцать минут разработал алгоритм нахождения кратчайшего пути. Он был опубликован через три года, в 1959 году.</p>
40 <p>"Однажды мы с моей невестой пили кофе на террасе кафе в Амстердаме. Там я примерно за двадцать минут разработал алгоритм нахождения кратчайшего пути. Он был опубликован через три года, в 1959 году.</p>
41 <p>Одна из причин, по которой алгоритм получился таким красивым, заключалась в том, что я создал его в уме, без карандаша и бумаги. Позже я узнал, что одно из преимуществ такого проектирования состоит в том, что при этом вы стараетесь максимально избегать сложностей.</p>
41 <p>Одна из причин, по которой алгоритм получился таким красивым, заключалась в том, что я создал его в уме, без карандаша и бумаги. Позже я узнал, что одно из преимуществ такого проектирования состоит в том, что при этом вы стараетесь максимально избегать сложностей.</p>
42 <p>Этот алгоритм стал, к моему удивлению, одним из краеугольных камней моей славы".</p>
42 <p>Этот алгоритм стал, к моему удивлению, одним из краеугольных камней моей славы".</p>
43 <p><strong>Эдсгер Дейкстра</strong>в интервью Филиппу Л. Франа</p>
43 <p><strong>Эдсгер Дейкстра</strong>в интервью Филиппу Л. Франа</p>
44 <p>С теорией разобрались - теперь давайте напишем код, реализующий алгоритм Дейкстры на языке Python. В качестве примера рассчитаем расстояние от вершины<strong>A</strong>до других вершин в нашем графе.</p>
44 <p>С теорией разобрались - теперь давайте напишем код, реализующий алгоритм Дейкстры на языке Python. В качестве примера рассчитаем расстояние от вершины<strong>A</strong>до других вершин в нашем графе.</p>
45 <p>Для работы нам понадобится heapq - один из модулей стандартной библиотеки Python, предназначенный для работы с кучами. Куча - структура данных, где каждый родительский узел имеет значение, меньшее или равное любому из его дочерних элементов.</p>
45 <p>Для работы нам понадобится heapq - один из модулей стандартной библиотеки Python, предназначенный для работы с кучами. Куча - структура данных, где каждый родительский узел имеет значение, меньшее или равное любому из его дочерних элементов.</p>
46 <p>Создадим функцию dijkstra с аргументами:</p>
46 <p>Создадим функцию dijkstra с аргументами:</p>
47 <p>graph - заданный граф;</p>
47 <p>graph - заданный граф;</p>
48 <p>start - начальная вершина.</p>
48 <p>start - начальная вершина.</p>
49 <p>Внутри функции создаём словарь distances, чтобы хранить расстояния от начальной вершины до всех остальных. Мы также создаём кучу priority_queue для выбора вершин с наименьшим текущим расстоянием.</p>
49 <p>Внутри функции создаём словарь distances, чтобы хранить расстояния от начальной вершины до всех остальных. Мы также создаём кучу priority_queue для выбора вершин с наименьшим текущим расстоянием.</p>
50 import heapq def dijkstra(graph, start): # Инициализация словаря для хранения расстояний # до каждой вершины. Сначала все расстояния бесконечны. distances = {vertex: float('infinity') for vertex in graph} # Расстояние до начальной вершины равно 0. distances[start] = 0 # Создаём приоритетную очередь для хранения вершин и их расстояний. priority_queue = [(0, start)]<p>Далее алгоритм в цикле обновляет расстояния до соседних вершин до тех пор, пока не найдёт кратчайшие расстояния для всех вершин. Результат выводится в виде словаря, где ключи - вершины, а значения - расстояния до них от точки<strong>A</strong>.</p>
50 import heapq def dijkstra(graph, start): # Инициализация словаря для хранения расстояний # до каждой вершины. Сначала все расстояния бесконечны. distances = {vertex: float('infinity') for vertex in graph} # Расстояние до начальной вершины равно 0. distances[start] = 0 # Создаём приоритетную очередь для хранения вершин и их расстояний. priority_queue = [(0, start)]<p>Далее алгоритм в цикле обновляет расстояния до соседних вершин до тех пор, пока не найдёт кратчайшие расстояния для всех вершин. Результат выводится в виде словаря, где ключи - вершины, а значения - расстояния до них от точки<strong>A</strong>.</p>
51 while priority_queue: # Извлекаем вершину с наименьшим расстоянием из очереди. current_distance, current_vertex = heapq.heappop(priority_queue) # Если текущее расстояние до вершины уже больше, чем сохранённое расстояние, игнорируем её. if current_distance &gt; distances[current_vertex]: continue # Рассмотрим все соседние вершины текущей вершины. for neighbor, weight in graph[current_vertex].items(): distance = current_distance + weight # Если найден более короткий путь до соседа, обновим расстояние. if distance &lt; distances[neighbor]: distances[neighbor] = distance heapq.heappush(priority_queue, (distance, neighbor)) return distances<p>Теперь рассчитаем для нашего графа кратчайшие расстояния от <strong>А</strong>до остальных вершин. Граф представим в виде словаря, где ключи - вершины, а значения - словари с соседними вершинами и весами рёбер.</p>
51 while priority_queue: # Извлекаем вершину с наименьшим расстоянием из очереди. current_distance, current_vertex = heapq.heappop(priority_queue) # Если текущее расстояние до вершины уже больше, чем сохранённое расстояние, игнорируем её. if current_distance &gt; distances[current_vertex]: continue # Рассмотрим все соседние вершины текущей вершины. for neighbor, weight in graph[current_vertex].items(): distance = current_distance + weight # Если найден более короткий путь до соседа, обновим расстояние. if distance &lt; distances[neighbor]: distances[neighbor] = distance heapq.heappush(priority_queue, (distance, neighbor)) return distances<p>Теперь рассчитаем для нашего графа кратчайшие расстояния от <strong>А</strong>до остальных вершин. Граф представим в виде словаря, где ключи - вершины, а значения - словари с соседними вершинами и весами рёбер.</p>
52 # Пример использования: graph = { 'A': {'B': 4, 'C': 7}, 'B': {'A': 4, 'D': 2, 'E': 8}, 'C': {'A': 7, 'D': 2, 'E': 5}, 'D': {'B': 2, 'C': 2, 'E': 1,'F': 4}, 'E': {'C': 5, 'D': 1, 'F': 11}, 'F': {'B': 8, 'D': 4, 'E': 11} }<p>Вызываем функцию dijkstra с начальной вершиной<strong>A</strong>и выводим в консоль результат.</p>
52 # Пример использования: graph = { 'A': {'B': 4, 'C': 7}, 'B': {'A': 4, 'D': 2, 'E': 8}, 'C': {'A': 7, 'D': 2, 'E': 5}, 'D': {'B': 2, 'C': 2, 'E': 1,'F': 4}, 'E': {'C': 5, 'D': 1, 'F': 11}, 'F': {'B': 8, 'D': 4, 'E': 11} }<p>Вызываем функцию dijkstra с начальной вершиной<strong>A</strong>и выводим в консоль результат.</p>
53 result = dijkstra(graph, 'A') # Выводим результат. print("Кратчайшие расстояния до каждой вершины:") for vertex, distance in result.items(): print(f"До вершины {vertex}: {distance}")<p>Бинго!</p>
53 result = dijkstra(graph, 'A') # Выводим результат. print("Кратчайшие расстояния до каждой вершины:") for vertex, distance in result.items(): print(f"До вершины {vertex}: {distance}")<p>Бинго!</p>
54 Кратчайшие расстояния до каждой вершины: До вершины A: 0 До вершины B: 4 До вершины C: 7 До вершины D: 6 До вершины E: 7 До вершины F: 10<p>Другой известный алгоритм для поиска кратчайшего пути - A* (читается как "А звезда" или "А стар"). По сути, это расширение алгоритма Дейкстры с дополнительными функциями для улучшения скорости. Разработали A* в 1968 году, используют - до сих пор в разных областях: от робототехники до навигации и геймдева.</p>
54 Кратчайшие расстояния до каждой вершины: До вершины A: 0 До вершины B: 4 До вершины C: 7 До вершины D: 6 До вершины E: 7 До вершины F: 10<p>Другой известный алгоритм для поиска кратчайшего пути - A* (читается как "А звезда" или "А стар"). По сути, это расширение алгоритма Дейкстры с дополнительными функциями для улучшения скорости. Разработали A* в 1968 году, используют - до сих пор в разных областях: от робототехники до навигации и геймдева.</p>
55 <p>Так же как и алгоритм Дейкстры, A* ищет расстояние от начальной точки до конечной. Но, в отличие от последнего, он учитывает не только расстояние от текущей точки до начальной, но и эвристическую оценку этого расстояния. В данном контексте "эвристическая" означает "примерная": функция не определяет точное расстояние от точки до цели, но подсказывает алгоритму приблизительную величину.</p>
55 <p>Так же как и алгоритм Дейкстры, A* ищет расстояние от начальной точки до конечной. Но, в отличие от последнего, он учитывает не только расстояние от текущей точки до начальной, но и эвристическую оценку этого расстояния. В данном контексте "эвристическая" означает "примерная": функция не определяет точное расстояние от точки до цели, но подсказывает алгоритму приблизительную величину.</p>
56 <p>Например, нам нужно найти кратчайший путь из города А в город В на карте. В качестве эвристики мы можем использовать расстояние "по прямой линии" (то есть "евклидово расстояние") от текущей точки до точки B. Это позволит оценить длину пути между текущей точкой и целью.</p>
56 <p>Например, нам нужно найти кратчайший путь из города А в город В на карте. В качестве эвристики мы можем использовать расстояние "по прямой линии" (то есть "евклидово расстояние") от текущей точки до точки B. Это позволит оценить длину пути между текущей точкой и целью.</p>
57 <em>Изображение: Skillbox Media</em><p>На графике выше изображены эвристические расстояния от промежуточных точек до конечной точки на карте, без учёта существующих дорог.</p>
57 <em>Изображение: Skillbox Media</em><p>На графике выше изображены эвристические расстояния от промежуточных точек до конечной точки на карте, без учёта существующих дорог.</p>
58 <p>Ещё одна популярная эвристика - манхэттенское расстояние. Её название происходит от системы улиц на острове Манхэттен в Нью-Йорке. Это сеть улиц, которые пересекаются под прямым углом, что делает её похожей на таблицу. Чтобы добраться от одной точки до другой, приходится двигаться вдоль улиц. Если представить эти улицы в виде координатной сетки, мы можем двигаться только вдоль осей X и Y, но не по диагонали.</p>
58 <p>Ещё одна популярная эвристика - манхэттенское расстояние. Её название происходит от системы улиц на острове Манхэттен в Нью-Йорке. Это сеть улиц, которые пересекаются под прямым углом, что делает её похожей на таблицу. Чтобы добраться от одной точки до другой, приходится двигаться вдоль улиц. Если представить эти улицы в виде координатной сетки, мы можем двигаться только вдоль осей X и Y, но не по диагонали.</p>
59 <p>Если у нас есть две точки с координатами (<strong>x1</strong>,<strong>y1</strong>) и (<strong>x2</strong>,<strong>y2</strong>), то манхэттенское расстояние между ними (M) вычисляется по следующей формуле:</p>
59 <p>Если у нас есть две точки с координатами (<strong>x1</strong>,<strong>y1</strong>) и (<strong>x2</strong>,<strong>y2</strong>), то манхэттенское расстояние между ними (M) вычисляется по следующей формуле:</p>
60 <em>Изображение: Skillbox Media</em><p>Попробуем разобраться на примере. Допустим, у нас есть точка<strong>A</strong> с координатами (2, 8) и точка<strong>B</strong> с координатами (4, 3).</p>
60 <em>Изображение: Skillbox Media</em><p>Попробуем разобраться на примере. Допустим, у нас есть точка<strong>A</strong> с координатами (2, 8) и точка<strong>B</strong> с координатами (4, 3).</p>
61 <em>Изображение: Skillbox Media</em><p>Подставляем координаты в формулу - получается, манхэттенское расстояние равно M = ∣4-2∣ + ∣3-8∣ = 2 + 5 = 7.</p>
61 <em>Изображение: Skillbox Media</em><p>Подставляем координаты в формулу - получается, манхэттенское расстояние равно M = ∣4-2∣ + ∣3-8∣ = 2 + 5 = 7.</p>
62 <p>Основная идея алгоритма A* - это определение двух значений для каждой вершины в графе:</p>
62 <p>Основная идея алгоритма A* - это определение двух значений для каждой вершины в графе:</p>
63 <ul><li><strong>g(n)</strong> - длина пути от начальной вершины до текущей вершины n.</li>
63 <ul><li><strong>g(n)</strong> - длина пути от начальной вершины до текущей вершины n.</li>
64 <li><strong>h(n)</strong> - эвристическая оценка длины от текущей вершины n до цели.</li>
64 <li><strong>h(n)</strong> - эвристическая оценка длины от текущей вершины n до цели.</li>
65 </ul><p>На каждом шаге алгоритм A* выбирает вершину с наименьшей суммой<strong>g(n) + h(n)</strong>и исследует её соседей. Это продолжается до тех пор, пока алгоритм не достигнет конечной цели.</p>
65 </ul><p>На каждом шаге алгоритм A* выбирает вершину с наименьшей суммой<strong>g(n) + h(n)</strong>и исследует её соседей. Это продолжается до тех пор, пока алгоритм не достигнет конечной цели.</p>
66 <p>Попробуем написать A* на Python для графа с эвристикой в виде манхэттенского расстояния. Здесь функция manhattan_distance вычисляет манхэттенское расстояние между двумя точками, а astar реализует алгоритм A* с использованием этого расстояния.</p>
66 <p>Попробуем написать A* на Python для графа с эвристикой в виде манхэттенского расстояния. Здесь функция manhattan_distance вычисляет манхэттенское расстояние между двумя точками, а astar реализует алгоритм A* с использованием этого расстояния.</p>
67 import heapq # Функция для вычисления манхэттенского расстояния между двумя точками def manhattan_distance(point1, point2): return abs(point1[0] - point2[0]) + abs(point1[1] - point2[1])<p>Реализация алгоритма A*:</p>
67 import heapq # Функция для вычисления манхэттенского расстояния между двумя точками def manhattan_distance(point1, point2): return abs(point1[0] - point2[0]) + abs(point1[1] - point2[1])<p>Реализация алгоритма A*:</p>
68 def astar(grid, start, goal): # Инициализация словарей для хранения стоимостей и предыдущих точек cost = {start: 0} came_from = {start: None} # Приоритетная очередь для хранения точек и их оценок (приоритетов) priority_queue = [(0, start)] while priority_queue: # Извлечение точки с минимальной оценкой current_cost, current_point = heapq.heappop(priority_queue) # Если достигнута целевая точка, завершаем алгоритм if current_point == goal: break # Рассмотрение соседних точек for neighbor in [(1, 0), (-1, 0), (0, 1), (0, -1)]: x, y = current_point[0] + neighbor[0], current_point[1] + neighbor[1] new_cost = cost[current_point] + 1 # Стоимость перемещения на одну ячейку # Проверка на наличие препятствия и обновление стоимости, если новый путь короче if 0 &lt;= x &lt; len(grid) and 0 &lt;= y &lt; len(grid[0]) and grid[x][y] == 0: if (x, y) not in cost or new_cost &lt; cost[(x, y)]: cost[(x, y)] = new_cost priority = new_cost + manhattan_distance((x, y), goal) # Оценка для приоритета heapq.heappush(priority_queue, (priority, (x, y))) came_from[(x, y)] = current_point<p>Восстановление пути:</p>
68 def astar(grid, start, goal): # Инициализация словарей для хранения стоимостей и предыдущих точек cost = {start: 0} came_from = {start: None} # Приоритетная очередь для хранения точек и их оценок (приоритетов) priority_queue = [(0, start)] while priority_queue: # Извлечение точки с минимальной оценкой current_cost, current_point = heapq.heappop(priority_queue) # Если достигнута целевая точка, завершаем алгоритм if current_point == goal: break # Рассмотрение соседних точек for neighbor in [(1, 0), (-1, 0), (0, 1), (0, -1)]: x, y = current_point[0] + neighbor[0], current_point[1] + neighbor[1] new_cost = cost[current_point] + 1 # Стоимость перемещения на одну ячейку # Проверка на наличие препятствия и обновление стоимости, если новый путь короче if 0 &lt;= x &lt; len(grid) and 0 &lt;= y &lt; len(grid[0]) and grid[x][y] == 0: if (x, y) not in cost or new_cost &lt; cost[(x, y)]: cost[(x, y)] = new_cost priority = new_cost + manhattan_distance((x, y), goal) # Оценка для приоритета heapq.heappush(priority_queue, (priority, (x, y))) came_from[(x, y)] = current_point<p>Восстановление пути:</p>
69 path = [] current = goal while current: path.append(current) current = came_from[current] path.reverse() return path<p>Выполнение алгоритма A*. Определение сетки 5 × 5. Препятствия обозначаются единицами в сетке.</p>
69 path = [] current = goal while current: path.append(current) current = came_from[current] path.reverse() return path<p>Выполнение алгоритма A*. Определение сетки 5 × 5. Препятствия обозначаются единицами в сетке.</p>
70 grid = [ [0, 0, 0, 0, 0], [0, 1, 1, 0, 0], [0, 0, 0, 1, 0], [0, 1, 0, 0, 0], [0, 0, 0, 0, 0] ] # Начальная и конечная точки start = (0, 0) goal = (4, 4) result_path = astar(grid, start, goal) # Вывод результата print("Путь от A до B:") for point in result_path: print(point)<p>В результате выполнения получим:</p>
70 grid = [ [0, 0, 0, 0, 0], [0, 1, 1, 0, 0], [0, 0, 0, 1, 0], [0, 1, 0, 0, 0], [0, 0, 0, 0, 0] ] # Начальная и конечная точки start = (0, 0) goal = (4, 4) result_path = astar(grid, start, goal) # Вывод результата print("Путь от A до B:") for point in result_path: print(point)<p>В результате выполнения получим:</p>
71 Путь от A до B: (0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (1, 4) (2, 4) (3, 4) (4, 4)<p>Этот код реализует A* для поиска кратчайшего пути в заданной сетке с использованием манхэттенского расстояния в качестве эвристической функции. В результате он выводит кратчайший путь от точки<strong>А</strong>до <strong>B</strong>.</p>
71 Путь от A до B: (0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (1, 4) (2, 4) (3, 4) (4, 4)<p>Этот код реализует A* для поиска кратчайшего пути в заданной сетке с использованием манхэттенского расстояния в качестве эвристической функции. В результате он выводит кратчайший путь от точки<strong>А</strong>до <strong>B</strong>.</p>
72 <p>Выбор между этими алгоритмами зависит от конкретной задачи и доступной информации.</p>
72 <p>Выбор между этими алгоритмами зависит от конкретной задачи и доступной информации.</p>
73 <p>Сравним их:</p>
73 <p>Сравним их:</p>
74 <ul><li>Алгоритм Дейкстры используется для нахождения кратчайшего пути от начальной вершины графа ко всем остальным. Алгоритм A* используется для нахождения кратчайшего пути от начальной вершины к заданной, учитывая эвристическую оценку расстояния.</li>
74 <ul><li>Алгоритм Дейкстры используется для нахождения кратчайшего пути от начальной вершины графа ко всем остальным. Алгоритм A* используется для нахождения кратчайшего пути от начальной вершины к заданной, учитывая эвристическую оценку расстояния.</li>
75 <li>Алгоритм Дейкстры рассматривает все вершины равнозначно и всегда выбирает вершину с наименьшим расстоянием до неё. Алгоритм A*, кроме этого, дополнительно использует эвристику. Это делает его более эффективным для больших графов или когда есть информация о приблизительной величине дистанции до цели.</li>
75 <li>Алгоритм Дейкстры рассматривает все вершины равнозначно и всегда выбирает вершину с наименьшим расстоянием до неё. Алгоритм A*, кроме этого, дополнительно использует эвристику. Это делает его более эффективным для больших графов или когда есть информация о приблизительной величине дистанции до цели.</li>
76 <li>Алгоритм Дейкстры может быть медленным для больших графов, так как исследует все вершины. Алгоритм A* в больших графах работает быстрее благодаря эвристике, которая позволяет сократить количество рассматриваемых вершин.</li>
76 <li>Алгоритм Дейкстры может быть медленным для больших графов, так как исследует все вершины. Алгоритм A* в больших графах работает быстрее благодаря эвристике, которая позволяет сократить количество рассматриваемых вершин.</li>
77 </ul><p>Таким образом, алгоритм Дейкстры будет эффективнее там, где нужно найти кратчайшие пути от одной вершины ко всем остальным и нет информации о примерной дистанции до цели. Если есть эвристическая информация, которая может помочь ускорить поиск, то лучшим выбором будет A*.</p>
77 </ul><p>Таким образом, алгоритм Дейкстры будет эффективнее там, где нужно найти кратчайшие пути от одной вершины ко всем остальным и нет информации о примерной дистанции до цели. Если есть эвристическая информация, которая может помочь ускорить поиск, то лучшим выбором будет A*.</p>
78 <a><b>Бесплатный курс по Python ➞</b>Мини-курс для новичков и для опытных кодеров. 4 крутых проекта в портфолио, живое общение со спикером. Кликните и узнайте, чему можно научиться на курсе. Смотреть программу</a>
78 <a><b>Бесплатный курс по Python ➞</b>Мини-курс для новичков и для опытных кодеров. 4 крутых проекта в портфолио, живое общение со спикером. Кликните и узнайте, чему можно научиться на курсе. Смотреть программу</a>