A*学习算法整合

学习A*算法所需的前置知识

  • Dijkstra算法

  • BFS优先搜索算法


为什么要学习A*算法?

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

A*算法

首先我们来引入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 ( x ) = g ( x ) + h ( x ) f(x)=g(x)+h(x) f(x)=g(x)+h(x)

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;
}

以下是利用pygame制成的可动态显示A*算法过程的图和代码:

如果随机生成的地图没有终点,呢么程序会报错,即不会执行

import pygame
import sys
import queue as Q
import random
import time


class Node(object):
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

    def __lt__(self, other):
        return self.a < other.a


class NS(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y


class pair(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y


ex = 29
ey = 39
q = Q.Queue()
qs = Q.Queue()
Map = [[0 for i in range(40)] for _ in range(30)]
vis = [[0 for i in range(40)] for _ in range(30)]
pre = [[0 for i in range(40)] for _ in range(30)]
dir = [[1, 0], [-1, 0], [0, 1], [0, -1]]
dis = [[100000 for i in range(40)] for _ in range(30)]


def calc(x, y):
    return (ex-x)*(ex-x)+(ey-y)*(ey-y)


def start():
    time.sleep(1)


def A_star():
    que = Q.PriorityQueue()
    dis[0][0] = 0
    que.put(Node(calc(0, 0)+dis[0][0], 0, 0))
    while not que.empty():
        st = que.get()

        if vis[st.b][st.c] == 1:
            continue
        vis[st.b][st.c] = 1
        q.put(NS(st.b, st.c))

        if st.b == ex and st.c == ey:
            break
        for i in range(4):
            xx = st.b+dir[i][0]
            yy = st.c+dir[i][1]
            if (xx >= 0) and (yy >= 0) and (xx <= ex) and (yy <= ey) and Map[xx][yy] == 0:
                if(dis[xx][yy] > dis[st.b][st.c]+1):
                    dis[xx][yy] = dis[st.b][st.c]+1
                    pre[xx][yy] = (st.b, st.c)
                    que.put(Node(dis[xx][yy]+calc(xx, yy), xx, yy))


stack = []


def path():
    if(dis[ex][ey] == 100000):
        return
    i = ex
    j = ey
    stack.append((i, j))
    # print(i, j)
    while i != 0 or j != 0:
        k1 = pre[i][j][0]
        k2 = pre[i][j][1]
        i = k1
        j = k2
        # print(i, j)
        stack.append((i, j))


def createMap():
    T = 700
    while T >= 0:
        T -= 1
        if Map[random.randint(1, 29)][random.randint(1, 39)] == 1:
            Map[random.randint(1, 29)][random.randint(1, 39)] = 0
        else:
            Map[random.randint(1, 29)][random.randint(1, 39)] = 1
    Map[29][39] = 0


pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("py")
Black = pygame.Color("black")
Green = pygame.Color("green")
Blue = pygame.Color("blue")
Red = pygame.Color("red")
fps = 20
fclock = pygame.time.Clock()
createMap()
screen.fill("grey")
for i in range(0, 30):
    for j in range(0, 40):
        pygame.draw.rect(screen, Black, (j*20, i*20, 20, 20), 1)
for i in range(30):
    for j in range(40):
        if(Map[i][j] == 1):
            pygame.draw.rect(screen, Red, (j*20, i*20, 20, 20), 0)

A_star()

path()
start()
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
    if not q.empty():
        st = q.get()
        pygame.draw.rect(screen, Blue, (st.y*20, st.x*20, 20, 20), 0)
    elif len(stack):
        s = stack.pop()
        pygame.draw.rect(screen, Green, (s[1]*20, s[0]*20, 20, 20), 0)

    fclock.tick(fps)
    pygame.display.update()ru

动态图:

扫描二维码关注公众号,回复: 12428908 查看本文章

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/yangzijiangac/article/details/112781254