A* е набор от стъпки (алгоритъм), който компютрите използват, за да намерят най-краткия или най-евтиния път между две места в граф (набор от възли и връзки между тях). Ако имате списък с места и колко струва (или колко време отнема) да се премине директно от едно място до друго, A* може бързо да открие най-добрия маршрут. Алгоритъмът е свързан с алгоритъма на Дийкстра — в общия случай, когато евристиката е нула, A* става еквивалентен на Дийкстра — но A* прави „интелигентни предположения“ (евристика), за да не разглежда ненужно много пътища. Това е подходящ метод, ако искате един добър път между две точки. Ако трябва да намерите много пътища за всички двойки възли в една и съща карта, има алгоритми като Флойд–Уоршал, които могат да са по-ефективни за тази задача. A* не е подходящ за задачи като задачата за пътуващия търговец, където трябва да посетите много места в едно пътуване.
Как работи A*
Основната идея на A* е да комбинира вече изминатия разход и оценката за оставащия разстояние, за да приоритизира кои възли да се изследват първо. За всеки възел алгоритъмът поддържа три стойности:
- g(n) — реалния разход от началния възел до възел n (колко струва вече пътят до тук);
- h(n) — евристична оценка за разхода от n до целта (оценка на оставащото разстояние);
- f(n) = g(n) + h(n) — оценка за общия разход през възел n.
Алгоритъмът използва две множества: open (възли, които предстои да се разгледат, обикновено реализирано като приоритетна опашка по f) и closed (възли, които вече са разгледани). Всяка стъпка A* вади от open възела с най-ниско f, разглежда съседите му и актуализира техните g/h/f стойности, докато не достигне целта.
Евристика (h)
Евристиката е важна за бързината и коректността на A*:
- Адмисибилна евристика: никога не надценява истинския минимален разход до целта. Ако h е адмисибилна, A* гарантира, че ще намери оптимален (най-кратък) път.
- Конзистентна (монотонна) евристика: за всяко ребро (n → m) важи h(n) ≤ cost(n,m) + h(m). Конзистентността гарантира, че f-стойността на възлите не намалява при разширяване и позволява проста реализация без повторни вмъквания в open.
- Примери за евристики в равнинни мрежи: Манхатънско разстояние (за движение само по вертикал/хоризонтал), Евклидово разстояние (за движение в произволна посока), Чебишев (за движение и по диагонал с еднаква цена).
Свойства и сложност
- Оптималност: Ако евристиката е адмисибилна (и особено ако е и конзистентна), A* намира оптимален път.
- Пълнота: A* е пълен при крайни графи и положителни ребърни тежести — ще намери път, ако такъв съществува.
- Времева и пространствена сложност: в най-лошия случай може да бъде експоненална по дълбочина/размер на графа, но в практиката — и с добра евристика — е много по-бърз от неевристични търсения като Дийкстра.
Основни стъпки (псевдокод като последователност)
- Постави началния възел в open с g(start)=0 и f=start.h.
- Докато open не е празно:
- Вземи възела current от open с най-ниско f.
- Ако current е целта → възстанови пътя чрез проследяване назад и приключи.
- Премести current в closed.
- За всеки съсед neighbor на current:
- Изчисли tentative_g = g(current) + cost(current, neighbor).
- Ако neighbor е в closed и tentative_g ≥ g(neighbor) → пропусни.
- Ако neighbor не е в open или tentative_g < g(neighbor):
- Актуализирай g(neighbor) = tentative_g, запази parent pointer към current, и пресметни f = g + h.
- Ако neighbor не е в open → вмъкни го в open.
Практически съвети за имплементация
- Използвайте ефективна приоритетна опашка (heap) за open; за поддръжка на актуализации може да е полезна структура, която поддържа намаление на ключ (decrease-key) или запис на записи с версия/идентификатор.
- Поддържайте parent (предходник) за всеки възел, за да може да възстановите пътя при достигане на целта.
- За големи карти помислете за варианти като итеративен дълбочинен A* (IDA*), Jump Point Search (за решетки) или предварително изчислени навигационни мрежи, за да намалите паметните и временни разходи.
- В реални приложения често се използват и практични оптимизации: ограничение на обхвата, използване на евристики, комбиниране с водещи алгоритми за предварително маршрутизиране и др.
Къде се използва A*
- Видео игри и симулации — за навигация на герои и NPC.
- Роботика и автономни превозни средства — за планиране на траектории.
- Географски информационни системи (карти и навигация).
- Всички задачи, където трябва бързо да се намери един най-добър път между две точки при познати преходни разходи.
Разширения и варианти
- Weighted A* — използва f = g + w·h (w > 1) за по-бързи, но евентуално ненапълно оптимални решения.
- IDA* — итеративно задълбочаване, което намалява паметните изисквания.
- Theta* и други алгоритми — търсят по-гладки или по-кратки траектории в непрекъснати пространства.
A* е много практичен и гъвкав инструмент за търсене на кратки пътища. С правилно избрана евристика и подходяща структура за данни той често намира оптималния маршрут много по-бързо от класическото безевристично търсене.