Алгоритмы Дейкстры и A*: поиск кратчайшего пути
Как найти самый быстрый путь на карте? Как ИИ в игре находит путь до цели, обходя стены?
Ответ — в алгоритмах поиска кратчайшего пути. Сегодня разберём два самых популярных:---
 Что решают эти алгоритмы
И Дейкстра, и A* ищут путь из точки A в точку B по графу, где:
- Вершины — узлы (например, перекрёстки, клетки карты, точки маршрута)
 - Рёбра — связи между ними с весами (расстояние, время, цена и т.д.)
 
Они гарантируют самый дешёвый путь, если веса неотрицательные.
---
 Алгоритм Дейкстры (Dijkstra)
Простой и надёжный: на каждом шаге выбираем узел с минимальной стоимостью и обновляем соседей.
- Не использует эвристик
 - Работает во всех графах без отрицательных весов
 - Может найти все кратчайшие пути от одной вершины
 
		Python:
	
	import heapq
def dijkstra(graph, start):
    dist = {v: float('inf') for v in graph}
    dist[start] = 0
    queue = [(0, start)]
    while queue:
        cost, u = heapq.heappop(queue)
        if cost > dist[u]:
            continue
        for v, weight in graph[u]:
            alt = dist[u] + weight
            if alt < dist[v]:
                dist[v] = alt
                heapq.heappush(queue, (alt, v))
    return dist
	
		Python:
	
	graph = {
    'A': [('B', 1), ('C', 4)],
    'B': [('C', 2), ('D', 5)],
    'C': [('D', 1)],
    'D': []
}
	Код на Си:
		C:
	
	#include <stdio.h>
#include <limits.h>
#define V 4  // количество вершин
int min_distance(int dist[], int visited[]) {
    int min = INT_MAX, index = -1;
    for (int i = 0; i < V; i++) {
        if (!visited[i] && dist[i] < min) {
            min = dist[i];
            index = i;
        }
    }
    return index;
}
void dijkstra(int graph[V][V], int start) {
    int dist[V];
    int visited[V] = {0};
    for (int i = 0; i < V; i++)
        dist[i] = INT_MAX;
    dist[start] = 0;
    for (int count = 0; count < V - 1; count++) {
        int u = min_distance(dist, visited);
        visited[u] = 1;
        for (int v = 0; v < V; v++) {
            if (!visited[v] && graph[u][v] && dist[u] != INT_MAX &&
                dist[u] + graph[u][v] < dist[v])
            {
                dist[v] = dist[u] + graph[u][v];
            }
        }
    }
    printf("Кратчайшие расстояния от вершины %d:\n", start);
    for (int i = 0; i < V; i++)
        printf("До %d = %d\n", i, dist[i]);
}
int main() {
    // Матрица смежности (веса)
    int graph[V][V] = {
        {0, 1, 4, 0},
        {0, 0, 2, 5},
        {0, 0, 0, 1},
        {0, 0, 0, 0}
    };
    dijkstra(graph, 0);  // из вершины 0
    return 0;
}
	---
 Алгоритм A* (A-star)
Это оптимизированная версия Дейкстры с «подсказками».
Он использует эвристику — оценку расстояния до цели.
Что такое эвристика в A*
Эвристика — это оценка оставшегося расстояния от текущей вершины до цели.Она помогает A* "предугадывать", где находится цель, и двигаться более умно, чем Дейкстра.
		Код:
	
	f(n) = g(n) + h(n)
	g(n)— расстояние от старта доn(как у Дейкстры)h(n)— приближённая оценка отnдо цели (например, Евклидово или Manhattan-расстояние)
		Python:
	
	import heapq
def a_star(graph, start, goal, heuristic):
    open_set = [(0, start)]
    g = {start: 0}
    came_from = {}
    while open_set:
        _, current = heapq.heappop(open_set)
        if current == goal:
            break
        for neighbor, cost in graph[current]:
            tentative_g = g[current] + cost
            if neighbor not in g or tentative_g < g[neighbor]:
                g[neighbor] = tentative_g
                f = tentative_g + heuristic(neighbor, goal)
                heapq.heappush(open_set, (f, neighbor))
                came_from[neighbor] = current
    return g.get(goal, float('inf'))
	Что происходит по шагам:
- g[n] — стоимость пути от старта до узла n (накапливаем её)
 - heuristic(n, goal) — оценка до цели
 - f = g + h — итоговая "стоимость" маршрута
 - Используется heapq — приоритетная очередь, которая выбирает вершину с наименьшим f
 
		Python:
	
	def manhattan(node, goal):
    x1, y1 = node
    x2, y2 = goal
    return abs(x1 - x2) + abs(y1 - y2)
	Как вызывать:
		Python:
	
	res = a_star(graph, 'A', 'D', manhattan)
print("Минимальное расстояние A → D:", res)
	Пример на Си, ориентирован на поле 5×5, где можно двигаться по 4 направлениям (вверх, вниз, влево, вправо), а 1 — проходимо, 0 — препятствие.
		Код:
	
	#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
#define N 5
typedef struct {
    int x, y;
    int g;  // стоимость от старта
    int f;  // общая стоимость (g + h)
} Node;
int goal_x = 4, goal_y = 4;
int heuristic(int x, int y) {
    return abs(goal_x - x) + abs(goal_y - y);  // Манхэттен
}
int in_bounds(int x, int y) {
    return x >= 0 && x < N && y >= 0 && y < N;
}
int is_passable(int grid[N][N], int x, int y) {
    return grid[x][y] == 1;
}
// простая очередь с приоритетом (по f)
void push(Node* open[], int* size, Node* n) {
    int i = *size;
    while (i > 0 && open[i - 1]->f > n->f) {
        open[i] = open[i - 1];
        i--;
    }
    open[i] = n;
    (*size)++;
}
Node* pop(Node* open[], int* size) {
    return open[--(*size)];
}
void a_star(int grid[N][N], int start_x, int start_y) {
    int closed[N][N] = {0};
    int came_from[N][N][2];
    Node* open[100];
    int open_size = 0;
    Node* start = malloc(sizeof(Node));
    start->x = start_x;
    start->y = start_y;
    start->g = 0;
    start->f = heuristic(start_x, start_y);
    push(open, &open_size, start);
    int dirs[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};
    while (open_size > 0) {
        Node* current = pop(open, &open_size);
        if (current->x == goal_x && current->y == goal_y) {
            printf("Путь найден:\n");
            int x = goal_x, y = goal_y;
            while (!(x == start_x && y == start_y)) {
                printf("(%d, %d) <- ", x, y);
                int px = came_from[x][y][0];
                int py = came_from[x][y][1];
                x = px;
                y = py;
            }
            printf("(%d, %d)\n", start_x, start_y);
            return;
        }
        closed[current->x][current->y] = 1;
        for (int i = 0; i < 4; i++) {
            int nx = current->x + dirs[i][0];
            int ny = current->y + dirs[i][1];
            if (!in_bounds(nx, ny) || !is_passable(grid, nx, ny) || closed[nx][ny])
                continue;
            int new_g = current->g + 1;
            Node* neighbor = malloc(sizeof(Node));
            neighbor->x = nx;
            neighbor->y = ny;
            neighbor->g = new_g;
            neighbor->f = new_g + heuristic(nx, ny);
            came_from[nx][ny][0] = current->x;
            came_from[nx][ny][1] = current->y;
            push(open, &open_size, neighbor);
        }
    }
    printf("Путь не найден.\n");
}
	Использование:
		C:
	
	int main() {
    int grid[N][N] = {
        {1, 1, 1, 1, 1},
        {0, 0, 0, 1, 0},
        {1, 1, 1, 1, 1},
        {1, 0, 0, 0, 1},
        {1, 1, 1, 1, 1}
    };
    a_star(grid, 0, 0);
    return 0;
}
	---
 Сравнение: Дейкстра vs A*
| Критерий | Дейкстра | A* | 
|---|---|---|
| Эвристика | Нет | Да | 
| Оптимальность | Гарантирована | Если эвристика допустима | 
| Скорость | Медленнее | Быстрее на практике | 
| Подходит для | Все кратчайшие пути | Целевой путь (start → goal) | 
| Гарантирует точный путь | Да | Да (если h не переоценивает) | 
---
 Где применяются?
- Маршруты в GPS (все пути из одной точки)
 - Планирование в графах без эвристик
 - Сети и маршрутизаторы
 
- Искусственный интеллект в играх
 - Роботы и дроны (путь от A до B)
 - Динамическая навигация
 
 Вывод
Алгоритмы поиска кратчайшего пути — основа навигации, планирования, анализа маршрутов.
- Дейкстра — надёжен, универсален
 - A\* — быстрее, если есть эвристика
 
	