a star search algorithm
是一种静态路网中求解最短路径的高效算法
可以看作是bfs的改进
其核心思路是
f(x) = g(x) + h(x)
我们定义初始状态-起点s,目标状态-终点t
x即为任意中间状态,在图遍历中,即中间节点
f(x)定义为从s出发,途径x到达t的最小代价估计
g(x)为s到x的实际代价
h(x)为x到t的最小代价估计,称为启发函数,我们无法知道x到t的实际距离h*(x),用h来近似估计它
使用a*需要满足2个条件
- h <= h* 即启发函数总是不超过实际的最短路径,这时a*算法一定能找到最短路径
- 对于任意2节点x,y,h(x)-h(y)<=D(x,y) 恒成立,其中D为xy的距离。这种情况下,任意节点最多被搜索一次。可以证明,满足该条件的h一定也满足条件1
可以发现,当h恒为0时,a退化为bfs,这时搜索不对h做任何估计,每次总是选取离s最近的节点做搜索,是一种最懒的情况。
也就是说,当h越接近h*时,搜索效率越高,但不能超过它
h越大时,对最短距离的估计越大胆
例题lc-752 打开转盘锁
#include <iostream>
#include <algorithm>
#include <vector>
#include <unordered_set>
#include <queue>
#include <functional>
using namespace std;
struct AStar {
string status_;
int f_, g_, h_;
static int getH(const string& status, const string& target) {
int ret = 0;
for (int i = 0; i < 4; i++) {
int dist = abs(int(status[i]) - int(target[i]));
ret += min(dist, 10 - dist);
}
return ret;
}
AStar(const string& status, const string& target, int g)
: status_(status), g_(g), h_(getH(status, target)) {
f_ = g_ + h_;
}
bool operator<(const AStar& that) const {
return f_ > that.f_;
}
};
class Solution {
public:
int openLock(vector<string>& deadends, string target) {
if (target == "0000") {
return 0;
}
unordered_set<string> deads(deadends.begin(), deadends.end());
if (deads.count("0000")) {
return -1;
}
auto num_prev = [](char x) -> char {
return (x == '0' ? '9' : x - 1);
};
auto num_succ = [](char x) -> char {
return (x == '9' ? '0' : x + 1);
};
auto get = [&](string& status) -> vector<string> {
vector<string> ret;
for (int i = 0; i < 4; i++) {
char num = status[i];
status[i] = num_prev(num);
ret.emplace_back(status);
status[i] = num_succ(num);
ret.emplace_back(status);
status[i] = num;
}
return ret;
};
// due to reloaded operator<, every AStar emplaced has been placed at
// the right rank
priority_queue<AStar> q;
q.emplace("0000", target, 0);
unordered_set<string> seen = {"0000"};
while (!q.empty()) {
AStar node = q.top();
q.pop();
for (auto&& next_status : get(node.status_)) {
if (!seen.count(next_status) && !deads.count(next_status)) {
if (next_status == target) {
return node.g_ + 1;
}
q.emplace(next_status, target, node.g_ + 1);
seen.insert(move(next_status));
}
}
}
return -1;
}
};
ref: https://oi-wiki.org/search/astar/
https://baijiahao.baidu.com/s?id=1675831725999372932&wfr=spider&for=pc
这个链接里的图很关键