К списку задач
Средне Решено: 0 Процент решений: 0%

Поиск A* на взвешенной сетке

Найдите самый дешёвый путь через сетку стоимостей местности с помощью A* — алгоритма поиска, на котором строится навигация в играх и робототехнике.

Чему вы научитесь

  • Находить самый дешёвый путь с очередью с приоритетом
  • Использовать манхэттенское расстояние как эвристику
  • Понять, почему допустимые эвристики сохраняют оптимальность

Условие

A* — классический алгоритм поиска пути в играх и робототехнике. Он перебирает клетки в порядке f = g + h, где g — уже уплаченная стоимость, а h — эвристическая оценка оставшейся стоимости.

В сетке записана стоимость каждой клетки: вход в клетку стоит её значение, а 0 — стена, в которую нельзя войти. Вы начинаете в start (её стоимость не платится) и можете двигаться вверх, вниз, влево или вправо.

Используйте A* с манхэттенским расстоянием |row - goal_row| + |col - goal_col| в качестве эвристики. Каждая открытая клетка стоит не меньше 1, поэтому эвристика никогда не завышает оценку и A* возвращает оптимальный ответ.

Реализуйте a_star_cost(grid, start, goal).

Входные данные

grid: Матрица стоимостей клеток (0 = стена).

start, goal: Позиции в виде [row, col].

Выходные данные

Верните минимальную суммарную стоимость пути до goal или -1, если до неё нельзя добраться (в том числе когда start или goal — стена).

Ограничения

1 ≤ строки, столбцы ≤ 100

0 ≤ каждая стоимость ≤ 9

Примеры

Пример 1
Ввод:
goal = [2, 2]
grid = [
    [1, 1, 1],
    [1, 0, 1],
    [1, 1, 1]
]
start = [0, 0]

Ожидаемый вывод:
expected = 4
Ввод:
std::vector<long long> goal = {2, 2};
std::vector<std::vector<long long>> grid = {
    {1, 1, 1},
    {1, 0, 1},
    {1, 1, 1}
};
std::vector<long long> start = {0, 0};

Ожидаемый вывод:
long long expected = 4;
Ввод:
long[] goal = new long[] {2, 2};
long[][] grid = new long[][] {
    new long[] {1, 1, 1},
    new long[] {1, 0, 1},
    new long[] {1, 1, 1}
};
long[] start = new long[] {0, 0};

Ожидаемый вывод:
long expected = 4;

Пояснение

Центр — стена. Два шага вправо и два вниз (или вниз, затем вправо) заходят в 4 клетки стоимостью 1, итого 4.

Пример 2
Ввод:
goal = [0, 2]
grid = [
    [1, 9, 1],
    [1, 9, 1],
    [1, 1, 1]
]
start = [0, 0]

Ожидаемый вывод:
expected = 6
Ввод:
std::vector<long long> goal = {0, 2};
std::vector<std::vector<long long>> grid = {
    {1, 9, 1},
    {1, 9, 1},
    {1, 1, 1}
};
std::vector<long long> start = {0, 0};

Ожидаемый вывод:
long long expected = 6;
Ввод:
long[] goal = new long[] {0, 2};
long[][] grid = new long[][] {
    new long[] {1, 9, 1},
    new long[] {1, 9, 1},
    new long[] {1, 1, 1}
};
long[] start = new long[] {0, 0};

Ожидаемый вывод:
long expected = 6;

Пояснение

Пройти прямо через 9 стоит 9 + 1 = 10. Спуститься, пройти по нижней строке и подняться обратно — это шесть клеток стоимостью 1, итого 6.

Как подступиться

Сначала попробуйте сами, затем открывайте подсказки по одной.

Подсказка 1

Используйте priority queue, упорядоченную по уже пройденной стоимости плюс Manhattan distance до цели.

Подсказка 2

Отслеживайте лучшую стоимость, найденную для каждой клетки, и раскрывайте клетку только если этот путь её улучшает.

Подсказка 3

Считайте стены и заблокированные стартовую или целевую клетки невозможными, и помните, что вход в стартовую клетку бесплатен.

Ожидаемая сложность

O(rows * cols log(rows * cols)) по времени, O(rows * cols) по дополнительной памяти

Ссылки

Это задание адаптировано для CodeUtility. Следуйте условию и ограничениям выше.

Учитесь у других

Решения сообщества

Пока нет опубликованных решений. Решите задание, чтобы поделиться первым.