Что такое алгоритм A* и чем он лучше Дейкстры?
- Что такое эвристика в поиске пути?
- Как в играх ищут путь на карте?
- Что такое допустимая эвристика?
A* — Дейкстра с подсказкой направления: вершины выбираются по f = g + h, где g — пройденное расстояние, h — оценка остатка до цели.
- Если h никогда не переоценивает расстояние (допустимая), найденный путь — кратчайший
- Чем точнее h, тем меньше вершин посещается; h = 0 — это обычная Дейкстра
А ещё На сетке: манхэттенское расстояние (4 направления), евклидово или октильное (8)
Подробно
Дейкстра расширяет поиск во все стороны одинаково — «кругом» от старта. Если цель одна и известно, где она, это расточительно. A* добавляет эвристику h(v) — оценку расстояния от вершины до цели — и выбирает из очереди вершину с наименьшим f(v) = g(v) + h(v). Поиск вытягивается в сторону цели.
Свойства эвристики:
- допустимая — никогда не переоценивает реальное оставшееся расстояние. Тогда A* гарантированно находит кратчайший путь;
- согласованная (монотонная) — для любого ребра
h(v) ≤ w(v, u) + h(u). Тогда каждую вершину достаточно обработать один раз; - h = 0 — A* превращается в Дейкстру;
- переоценивающая эвристика ускоряет поиск, но путь может оказаться не кратчайшим — иногда это сознательный выбор в играх.
Эвристики на сетке:
- 4 направления движения — манхэттенское расстояние
|dx| + |dy|; - 8 направлений — октильное или чебышёвское;
- свободное движение — евклидово расстояние.
Применения: навигация в играх и роботах, маршруты на картах (с дополнительными ускорениями вроде иерархий дорог), решение головоломок.
Пример
import heapq
def a_star(grid, start, goal):
h = lambda p: abs(p[0] - goal[0]) + abs(p[1] - goal[1]) # манхэттен
g = {start: 0}
parent = {start: None}
heap = [(h(start), start)]
while heap:
_, v = heapq.heappop(heap)
if v == goal:
break
for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)):
u = (v[0] + dr, v[1] + dc)
if 0 <= u[0] < len(grid) and 0 <= u[1] < len(grid[0]) and grid[u[0]][u[1]] != "#":
if g[v] + 1 < g.get(u, float("inf")):
g[u], parent[u] = g[v] + 1, v
heapq.heappush(heap, (g[u] + h(u), u))
return g.get(goal)Что хотят услышать
- Формула f = g + h и роль эвристики.
- Допустимость как условие кратчайшего пути.
- Связь с Дейкстрой (h = 0).
- Примеры эвристик для сетки.
Частые ошибки
- Использовать переоценивающую эвристику и ждать кратчайший путь.
- Брать евклидово расстояние на сетке с 4 направлениями — допустимо, но медленнее манхэттенского.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✓A* выбирает вершины по f = g + h, где h — оценка остатка до цели; при допустимой h путь кратчайший
- ✗A* работает только на графах без весов
- ✗A* — это Дейкстра, которая обходит граф в обратную сторону от цели к старту и поэтому всегда посещает меньше вершин при любой эвристике
- ✗Эвристика h может переоценивать расстояние без потери оптимальности
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.