Алгоритм A*: различия между версиями
Перейти к навигации
Перейти к поиску
Ctrlalt (обсуждение | вклад) Нет описания правки |
Ctrlalt (обсуждение | вклад) Нет описания правки |
||
Строка 1: | Строка 1: | ||
== Общая схема перехода от Дейкстры к A* == | |||
* Дейкстра ищет кратчайшие пути от заданной начальной вершины до всех остальных. A* ищет кратчайший путь от заданной начальной вершины до заданной конечной. | |||
* Понадобится эвристическая функция h(v), делающая предположение о том, сколько ещё нужно пройти от вершины v до конечной вершины. Функция h() никогда не должна переоценивать это расстояние (но может недооценивать). | |||
* В Дейкстре мы использовали массив dist[]: dist[v] — кратчайшее расстояние от стартовой вершины до вершины v. Теперь мы дополнительно используем массив distH[]: distH[v] — это оценённая длина пути из стартовой вершины в конечную через вершину v. Очевидно, distH[v] всегда равно dist[v] + h(v). | |||
* Будем сравнивать непосещённые вершины и определять наиболее перспективного соседа не по dist[], а по distH[]. | |||
* Заметим, что если h() всегда возвращает 0, то A* превращается в алгоритм Дейкстры. | |||
{|width=100% | |||
|width=50%| | |||
{|width=100% | |||
|width=50%| | |||
int dijkstra(vector<vector<pair<int, int>>> &graph, int start, int finish) { | |||
vector<vector<int>> dist(size, vector<int>(size, 1e9)); | |||
set<pair<int, int>> q; | |||
dist[start] = 0; | |||
q.insert({ dist[start], start }); | |||
while (!q.empty()) { | |||
int v = q.begin()->second; | |||
q.erase(q.begin()); | |||
if (v == finish) | |||
return dist[v]; | |||
for (auto &[to, w] : graph[v]) { | |||
if (dist[to] > dist[v] + w) { | |||
q.erase({ dist[to], to }); | |||
dist[to] = dist[v] + 1; | |||
q.insert({ dist[to], to }); | |||
} | |||
} | |||
} | |||
return 1e9; | |||
} | |||
|width=50%| | |||
int aStar(vector<vector<pair<int, int>>> &graph, int start, int finish) { | |||
vector<vector<int>> dist(size, vector<int>(size, 1e9)); | |||
{{Changed|1=vector<vector<int>> distH(size, vector<int>(size, 1e9));}} | |||
set<pair<int, int>> q; | |||
dist[start] = 0; | |||
{{Changed|1=distH[start] = dist[start] + h(start);}} | |||
q.insert({ {{Changed|distH}}[start], start }); | |||
while (!q.empty()) { | |||
int v = q.begin()->second; | |||
q.erase(q.begin()); | |||
if (v == finish) | |||
return dist[v]; | |||
for (auto &[to, w] : graph[v]) { | |||
if (dist[to] > dist[v] + w) { | |||
q.erase({ {{Changed|distH}}[to], to }); | |||
dist[to] = dist[v] + 1; | |||
{{Changed|1=distH[to] = dist[to] + h(to);}} | |||
q.insert({ {{Changed|distH}}[to], to }); | |||
} | |||
} | |||
} | |||
return 1e9; | |||
} | |||
|} | |||
== 15 Puzzle == | == 15 Puzzle == | ||
{| | {|width=100% | ||
|colspan=2| | |colspan=2| | ||
'''Board''' | '''Board''' | ||
Строка 65: | Строка 135: | ||
return "NO SOLUTION"; | return "NO SOLUTION"; | ||
map<Board, int> dist, distH, pred; | |||
set<pair<int, Board>> q; | set<pair<int, Board>> q; | ||
dist[board] = 0; | |||
dist[board] | distH[board] = dist[board] + board.manhattanHeuristic; | ||
pred[board] = -1; | pred[board] = -1; | ||
q.insert({ distH[board], board }); | |||
static vector<int> dy = { -1, 0, 1, 0 }; | static vector<int> dy = { -1, 0, 1, 0 }; | ||
Строка 77: | Строка 148: | ||
while (!q.empty()) { | while (!q.empty()) { | ||
auto | auto v = *q.begin()->second; | ||
q.erase(q.begin()); | q.erase(q.begin()); | ||
Строка 89: | Строка 160: | ||
Board to = v.move(dy[d], dx[d]); | Board to = v.move(dy[d], dx[d]); | ||
if (auto it = dist.find(to); it == dist.end() || | if (auto it = dist.find(to); it == dist.end() || it->second > dist[v] + 1) { | ||
q.erase({ distH[to], to }); | |||
q.erase({ | dist[to] = dist[v] + 1; | ||
dist[to] = | distH[to] = dist[to] + to.manhattanHeuristic; | ||
pred[to] = d; | pred[to] = d; | ||
q.insert({ | q.insert({ distH[to], to }); | ||
} | } | ||
} | } | ||
Строка 197: | Строка 268: | ||
|} | |} | ||
== Knight Path == | |||
int aStar(int size, int sy, int sx, int fy, int fx) { | |||
vector<vector<int>> dist(size, vector<int>(size, 1e9)); | |||
vector<vector<int>> distH(size, vector<int>(size, 1e9)); | |||
set<pair<int, pair<int, int>>> q; | |||
dist[sy][sx] = 0; | |||
distH[sy][sx] = dist[sy][sx] + (abs(sy - fy) + abs(sx - fx)) / 3; | |||
q.insert({ distH[sy][sx], { sy, sx } }); | |||
while (!q.empty()) { | |||
auto [y, x] = q.begin()->second; | |||
q.erase(q.begin()); | |||
if (y == fy && x == fx) | |||
return dist[y][x]; | |||
static int dy[] = { -2, -2, -1, 1, 2, 2, 1, -1 }; | |||
static int dx[] = { -1, 1, 2, 2, 1, -1, -2, -2 }; | |||
for (int d = 0; d < 8; d++) { | |||
int ty = y + dy[d], tx = x + dx[d]; | |||
if (0 <= ty && ty < size && 0 <= tx && tx < size && dist[ty][tx] > dist[y][x] + 1) { | |||
q.erase({ distH[ty][tx], { ty, tx } }); | |||
dist[ty][tx] = dist[y][x] + 1; | |||
distH[ty][tx] = dist[ty][tx] + (abs(ty - fy) + abs(tx - fx)) / 3; | |||
q.insert({ distH[ty][tx], { ty, tx } }); | |||
} | |||
} | |||
} | |||
return 1e9; | |||
} | |||
== Ссылки == | == Ссылки == |
Версия от 01:27, 7 августа 2021
Общая схема перехода от Дейкстры к A*
- Дейкстра ищет кратчайшие пути от заданной начальной вершины до всех остальных. A* ищет кратчайший путь от заданной начальной вершины до заданной конечной.
- Понадобится эвристическая функция h(v), делающая предположение о том, сколько ещё нужно пройти от вершины v до конечной вершины. Функция h() никогда не должна переоценивать это расстояние (но может недооценивать).
- В Дейкстре мы использовали массив dist[]: dist[v] — кратчайшее расстояние от стартовой вершины до вершины v. Теперь мы дополнительно используем массив distH[]: distH[v] — это оценённая длина пути из стартовой вершины в конечную через вершину v. Очевидно, distH[v] всегда равно dist[v] + h(v).
- Будем сравнивать непосещённые вершины и определять наиболее перспективного соседа не по dist[], а по distH[].
- Заметим, что если h() всегда возвращает 0, то A* превращается в алгоритм Дейкстры.
15 Puzzle
Knight Pathint aStar(int size, int sy, int sx, int fy, int fx) { vector<vector<int>> dist(size, vector<int>(size, 1e9)); vector<vector<int>> distH(size, vector<int>(size, 1e9)); set<pair<int, pair<int, int>>> q; dist[sy][sx] = 0; distH[sy][sx] = dist[sy][sx] + (abs(sy - fy) + abs(sx - fx)) / 3; q.insert({ distH[sy][sx], { sy, sx } }); while (!q.empty()) { auto [y, x] = q.begin()->second; q.erase(q.begin()); if (y == fy && x == fx) return dist[y][x]; static int dy[] = { -2, -2, -1, 1, 2, 2, 1, -1 }; static int dx[] = { -1, 1, 2, 2, 1, -1, -2, -2 }; for (int d = 0; d < 8; d++) { int ty = y + dy[d], tx = x + dx[d]; if (0 <= ty && ty < size && 0 <= tx && tx < size && dist[ty][tx] > dist[y][x] + 1) { q.erase({ distH[ty][tx], { ty, tx } }); dist[ty][tx] = dist[y][x] + 1; distH[ty][tx] = dist[ty][tx] + (abs(ty - fy) + abs(tx - fx)) / 3; q.insert({ distH[ty][tx], { ty, tx } }); } } } return 1e9; } Ссылки |