A*算法

前言

为了弥补之前简陋的JAVA大作业,所以我决定学习一下A* 算法,据说A* 算法的效率 > Dijkstra算法 和 优先搜索(BFS)算法,此BFS非彼BFS希望看到这篇文章的人,能分清楚,当然A*算法的高效之处也是继承了此BFS的高效,但为什么不用此BFS呢,请看正题。

正题

首先我们来引入Dijkstra算法,首先我们明白Dijkstra算法的时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn)的,如果了解Dijkstra算法的,是知道的Dijkstra是盲目的寻找图中的顶点,直到对所有点做了松弛操作后,才算完成搜索,但这样就会利用很多完全不可能的点,这样虽然可以找到最短路,但是效率略低,时间复杂度稳定在 O ( n l o g n ) O(nlogn) O(nlogn)
接下来们引入优先搜索算法(BFS)这个算法的时间复杂度也是 O ( n l o g n ) O(nlogn) O(nlogn)(指最坏时间复杂度),这个算法其实改良一下就成为A* 了,但是我们为了方便理解我们先讲他的简版,在讲它之前我们引入一个启发函数。
在这里插入图片描述

f ( n ) f(n) f(n) 代表 从起点到终点的综合预估花费, g ( n ) g(n) g(n) 代表起点到 n n n 节点的实际花费, h ( n ) h(n) h(n) 代表从 n n n 节点到终点的预估花费。
由于 f ( n ) f(n) f(n) 代表是当前状态最理想的花费,所以我们通过这种启发函数搜索到终点后得到的答案一定是最优的,那么BFS的从广度优先搜索成为优先搜索只需要将队列边为优先队列,每次取预估花费最小的即可,对于网格图的 h ( n ) h(n) h(n) 我们只需要利用欧几里得求出贡献即可。那么这种写法就会避免使用完全没有用的节点,呢么为什么我们不采取呢,主要原因是它的路径不一定是最短的。所以我们不采用这种方法。
那么A* 是如何实现的呢,其实很简单,我们将Dijkstra小改一下,按照优先搜索的写法,并且如果遇到终点直接结束即可,这就是A* 算法,下面我们来比较一下其高效成度。

展示一下A* 网格图寻路的效果图,并且含有遍历点的图,含未被使用的点的概率。
在这里插入图片描述
在这里插入图片描述

实现代码:

#include <bits/stdc++.h>
using namespace ::std;
const int N = 2e3 + 5;
const int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};
struct Node {
  int f, x, y;
  bool operator<(const Node& b) const { return f > b.f; }
};

class A_Star {
 public:
  A_Star(){};
  A_Star(int sx, int sy, int ex, int ey, int n, int m)
      : sx(sx), sy(sy), ex(ex), ey(ey), n(n), m(m) {}
  void scan();
  void Ashow();

 private:
  int sx, sy, ex, ey, n, m;
  static int vis[N][N];
  static int Map[N][N];
  static int dis[N][N];
  static int path[N][N][2];
  void Dijkstra();
  int Dis(int dx, int dy);
};
int A_Star::vis[N][N] = {0};
int A_Star::Map[N][N] = {0};
int A_Star::dis[N][N] = {0};
int A_Star::path[N][N][2] = {0};
int A_Star::Dis(int dx, int dy) {
  return dis[dx][dy] + abs(dx - ex) + abs(dy - ey);
}
void A_Star::scan() {
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      Map[i][j] = 0;
      dis[i][j] = 0x3f3f3f3f;
    }
  }
}
void A_Star::Ashow() {
  Dijkstra();
  vis[ex][ey] = 3;
  int ans = 0;
  for (int i = path[ex][ey][0], j = path[ex][ey][1]; i && j;) {
    vis[i][j] = 3;
    int k1 = path[i][j][0];
    int k2 = path[i][j][1];
    i = k1, j = k2;
  }
  // cout << vis[1][3] << endl;
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      if (vis[i][j] == 3)
        cout << "*";
      else
        cout << ".";
    }
    puts("");
  }
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      if (vis[i][j])
        ans++;
      cout << vis[i][j];
    }
    puts("");
  }
  cout << endl;
  int x = __gcd(n * n, n*n - ans);
  cout << (n * n - ans) / x << '/' << n * n / x << endl;
  cout << (1.0 * (n * n - ans)) / (n * n * 1.0) << endl;
}
void A_Star::Dijkstra() {
  priority_queue<Node> q;
  while (!q.empty()) {
    q.pop();
  }
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      dis[i][j] = 0x3f3f3f3f;
    }
  }
  Node st, en;
  dis[sx][sy] = 0;
  st.x = sx, st.y = sy;
  st.f = Dis(sx, sy);
  q.push(st);
  while (!q.empty()) {
    st = q.top();
    q.pop();
    if (vis[st.x][st.y])
      continue;
    vis[st.x][st.y] = 1;
    if (st.x == ex && st.y == ey)
      return;
    for (int i = 0; i < 4; i++) {
      int xx = st.x + dir[i][0];
      int yy = st.y + dir[i][1];
      if (xx <= 0 || yy <= 0 || xx > n || yy > m || Map[xx][yy])
        continue;
      if (dis[xx][yy] > dis[st.x][st.y] + 1) {
        dis[xx][yy] = dis[st.x][st.y] + 1;
        path[xx][yy][0] = st.x, path[xx][yy][1] = st.y;
        if (!vis[xx][yy]) {
          en.x = xx, en.y = yy;
          en.f = Dis(xx, yy);
          q.push(en);
        }
      }
    }
  }
}
int main() {
  int n;
  cin >> n;
  A_Star T(1, 1, n, n, n, n);
  T.scan();
  T.Ashow();
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值