【算法】【寻路】启发式搜索之a*算法

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个条件

  1. h <= h* 即启发函数总是不超过实际的最短路径,这时a*算法一定能找到最短路径
  2. 对于任意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
这个链接里的图很关键

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值