A星寻路算法

文章目录

  • A星寻路算法
    • 三种寻路算法:
    • A星寻路算法思想
    • A星寻路准备
    • A星寻路过程
    • A星寻路代码(完整)

三种寻路算法:

  • 深度寻路算法:不一定能找到最佳路径,但是寻路快速,只能走直线。
  • 广度寻路算法:一定能找到最短路径,但是开销大,时间慢,只能走直线。
  • A星寻路算法(常用):一定能找到最短路径,可以走直线和斜线,而且开销较小,常用于大型地图的寻路

A星寻路算法思想

引入: 狼吃羊模型。

狼捕猎羊:如果抓到了就加100分;如果狼不动,每分钟减2分;如果狼抓捕时会跑,跑步每分钟减5分;

​ 狼会饿 ,饿的时候每分钟减10分。 有一个积分的概念在这里面。结果会发现狼会站在原地不动

​ 因为狼直到,抓住羊很困难,跑步时会扣分,饿时会扣分,不动时也会扣分。但是人工智能狼计算出了站着不动时扣分的代价最低,而干其他事代价都高,因此狼会自动选择代价最低的方式,一动不动

​ 之后又加了设定:原地不动每分钟也扣分,而且是线性扣分。结果你会发现狼从一开始就会自杀

同理,自杀是代价最小的选择(即分数最高,如果你干其他的事,则可能会负分,所以狼会选择自杀)。

A星寻路算法也引入了这一概念,即通过计算和量化行走的各个方向的代价,来选择最优路径

  • 公式: f = g + h
  • f: 设定其为最终评估代价
  • g:起点到当前点的已经付出的代价
  • h:起点到终点的预期代价
  • 通过比较各条路线的最终代价,选择最小代价,即为合适的路径,也为最短路径

A星寻路准备

地图行列数,方向枚举,地图,辅助地图的设计等在此不描述,具体请看之前我写的前两种寻路算法的博客。
广度寻路算法
深度寻路算法

  • 记录坐标点的类型,GetH和GetF函数即为计算各种代价的函数,稍后会介绍。一个重载用来比较当前点是否到达终点

    struct MyPoint{int row, col;int f, g, h;bool operator==(const MyPoint& p){return (row == p.row && col == p.col);}void getH(int r, int c);void getF(){f = g + h;}
    };
    
  • 存储位置节点的树结构,含有构造函数用来构建树节点,vector数组存储多个节点:因为一个父亲会有多个孩子的情况。

    //树节点类型
    struct treeNode{MyPoint             pos;treeNode*           pParent;vector<treeNode*> child;treeNode(const MyPoint& p){pos = p;pParent = NULL;}
    };
    
  • 判断是否能走的函数,用于判断地图某个点是否能走,即不为墙,没越界,没走过,则能走。

    //判断pos点能不能走,能返回true 不能走返回false
    bool canWalk(int map[ROWS][COLS], bool pathMap[ROWS][COLS], MyPoint pos){//越界的不能走if (pos.row < 0 || pos.row >= ROWS ||pos.col < 0 || pos.col >= COLS) return false;//障碍物不能走if (1 == map[pos.row][pos.col]) return false;//走过不能走if (true == pathMap[pos.row][pos.col]) return false;return true;
    }
    
  • 数据的准备,注意itMin迭代器用于寻找最小节点(下面介绍)。

        INUM map[ROW][COL] ={{0,0,0,0,1,0,0,0,0,0},{0,0,0,0,1,0,0,0,0,0},{0,0,0,1,1,0,1,0,0,0},{0,0,0,0,1,0,1,0,0,0},{0,0,0,0,1,0,1,0,0,0},{0,0,1,0,1,0,0,0,0,0},{0,0,0,0,1,0,0,0,0,0},{0,0,0,0,0,0,1,0,0,0},{0,0,0,0,1,1,0,0,0,0},{0,0,0,0,1,0,0,0,0,0},};//起始点和终点Mypoint Begpos = { 1,1 };Mypoint Endpos = { 6,5 };//辅助地图BOOL pathMap[ROW][COL] = { false };//创建树根TreeNode* pRoot = new TreeNode(Begpos);vector<TreeNode*> buff;   //存储数组vector<TreeNode*>::iterator itMin;TreeNode* pCurrent = pRoot;  //记录当前节点位置TreeNode* pTemp = nullptr;   //试探节点BOOL isFindEnd = false;
    

A星寻路过程

假定直着走的代价为10,斜着走的代价为14

  • 首先计算起点位置周围八个方向付出代价(蓝色),此代价为付出的代价 g

  • 然后再计算起点到终点的代价(如何计算:数格子即可,某个点到终点的格子数,只能行列,不能斜着),此代价为预期代价h,可以发现 最终代价=付出+预期,可以得到一个最小的代价点,即右下角的斜着的点

    这个点即是我们下一步要走的点依次类推,在下个点上,再次计算周围代价最小的点,然后再次移动

  • 注意:标记起始点和每个移动到的点为已经走过点,即下一次不会重复移动到这个点。

  • 在移动到的点处(代价最小点),继续遍历八个方向,除了墙壁已经走过点,继续计算最终代价,找到最终代价小的点,移动。

  • 注意:如果你移动到了一个死胡同,则必须回退,如何回退,请注意:我们事先准备了一个容器vector,来存储我们每次遍历的方向的节点,即我们把每一个方向都创建一个节点,然后节点入树节点再入容器,当我们走到死胡同时,通过找到容器内的最小元素(即是代价最小点,但是这个点是死胡同),然后把他删除,则再次找一个代价最小点然后移动到它那里去。如果地图没有终点,则可以想到,容器会一直删除,然后为空,此时则退出,没有终点。

  • 关于如何移动:准备一个试探点,试探每个方向,进行适当的row和col的变化,注意加上g(付出代价),然后判断能否走,依次计算代价,入树,保存容器,当前点移动到最小代价的点,删除最小代价点,以当前点的位置和终点比较来看是否到达了终点。

A星寻路代码(完整)

#include <iostream>
#include <vector>
using namespace std;const int ROW = 10;
const int COL = 10;
const int ZXDJ = 10;   //直线代价
const int XXDJ = 14;   //斜线代价
enum Dir { p_up, p_down, p_left, p_right, p_lup, p_ldown, p_rup, p_rdown };
struct Mypoint
{int row;int col;int f, g, h;bool operator==(const Mypoint& pos){return (pos.row == row && pos.col == col);}void GetH(const Mypoint& Begpos, const Mypoint& Endpos);void GetF(){f = g + h;}
};//树结构存储节点
struct TreeNode
{Mypoint pos;TreeNode* pParent;vector<TreeNode*> pChild;  //存储多个孩子节点的容器//构造函数TreeNode(const Mypoint& pos){this->pos = pos;pParent = nullptr;}
};bool CanWalk(int map[ROW][COL], bool pathMap[ROW][COL], const Mypoint& pos);
int main()
{int map[ROW][COL] ={{0,0,0,0,1,0,0,0,0,0},{0,0,0,0,1,0,0,0,0,0},{0,0,0,1,1,0,1,0,0,0},{0,0,0,0,1,0,1,0,0,0},{0,0,0,0,1,0,1,0,0,0},{0,0,1,0,1,0,0,0,0,0},{0,0,0,0,1,0,0,0,0,0},{0,0,0,0,0,0,1,0,0,0},{0,0,0,0,1,1,0,0,0,0},{0,0,0,0,1,0,0,0,0,0},};//起始点和终点Mypoint Begpos = { 1,1 };Mypoint Endpos = { 6,5 };//辅助地图bool pathMap[ROW][COL] = { false };//创建树根TreeNode* pRoot = new TreeNode(Begpos);vector<TreeNode*> buff;   //存储数组vector<TreeNode*>::iterator itMin;TreeNode* pCurrent = pRoot;  //记录当前节点TreeNode* pTemp = nullptr; //试探节点bool isFindEnd = false;//开始寻路while (1){//1. 某个点八个方向依次遍历 计算g代价for (int i = 0; i < 8; ++i){//确定试探点的属性pTemp = new TreeNode(pCurrent->pos);switch (i){case p_up:pTemp->pos.row--;pTemp->pos.g += ZXDJ;break;case p_down:pTemp->pos.row++;pTemp->pos.g += ZXDJ;break;case p_left:pTemp->pos.col--;pTemp->pos.g += ZXDJ;break;case p_right:pTemp->pos.col++;pTemp->pos.g += ZXDJ;break;case p_lup:pTemp->pos.row--;pTemp->pos.col--;pTemp->pos.g += XXDJ;break;case p_ldown:pTemp->pos.row++;pTemp->pos.col--;pTemp->pos.g += XXDJ;break;case p_rup:pTemp->pos.row--;pTemp->pos.col++;pTemp->pos.g += XXDJ;break;case p_rdown:pTemp->pos.row++;pTemp->pos.col++;pTemp->pos.g += XXDJ;break;}//判断他们能不能走,能走的计算h及f 入树  存储在buff数组if (CanWalk(map, pathMap, pTemp->pos)){   //能走//计算代价pTemp->pos.GetH(Begpos, Endpos);pTemp->pos.GetF();//放入树中pCurrent->pChild.push_back(pTemp);pTemp->pParent = pCurrent;//存入数组buff.push_back(pTemp);//标记走过这个点pathMap[pTemp->pos.row][pTemp->pos.col] = true;}else{//不能走则直接删除这个节点delete pTemp;pTemp = nullptr;}}// 找出数组中存储的最小代价的节点并删除itMin = buff.begin();   //找最小for (auto it = buff.begin(); it != buff.end(); ++it){itMin = ((*itMin)->pos.f < (*it)->pos.f) ? itMin : it;}//移动pCurrent = *itMin;//删除最小代价节点buff.erase(itMin);//有没有到达终点if (pCurrent->pos == Endpos){isFindEnd = true;break;}//没有终点,自然一直删除节点,则buff为空if (buff.size() == 0){break;}}if (isFindEnd){cout << "找到终点了!\n";while (pCurrent){cout << "(" << pCurrent->pos.row << "," << pCurrent->pos.col << ")";pCurrent = pCurrent->pParent;}}else{cout << "没有找到终点!\n";}return 0;
}bool CanWalk(int map[ROW][COL], bool pathMap[ROW][COL], const Mypoint& pos)
{//如果越界if (pos.row < 0 || pos.col < 0 || pos.row >= ROW || pos.col >= COL){return false;}//如果是墙if (map[pos.row][pos.col]){return false;}//如果已经走过if (pathMap[pos.row][pos.col]){return false;}return true;
}void Mypoint::GetH(const Mypoint& Begpos, const Mypoint& Endpos)
{int temp_x = (Endpos.col > Begpos.col) ? (Endpos.col - Begpos.col) : (Begpos.col - Endpos.col);int temp_y = (Endpos.row > Begpos.row) ? (Endpos.row - Begpos.row) : (Begpos.row - Endpos.row);h = temp_x + temp_y;return;
}

终点row,col(7,7):

终点row,col(6,5)

A星寻路算法详解(完整代码+图片演示)相关推荐

  1. 【A星算法】A星寻路算法详解(小白也可以看懂+C#代码+零基础学习A*)

    1.问题背景 在制作RPG游戏角色和NPC移动时,需要角色自动避开障碍物,到达终点 怎么快速找到一条到达终点的路径? 使用a星寻路算法 2.A星算法的思路 绿色:起点:红色:终点 :黑色:障碍物 新增 ...

  2. 谱聚类算法详解及代码实现

    谱聚类算法详解及代码实现 文章目录 谱聚类算法详解及代码实现 参考 关于谱聚类介绍 谱聚类概述 谱聚类前置知识 无向权重图 邻接矩阵 度矩阵 拉普拉斯矩阵 相似度矩阵 确定目标函数 初始化目标函数(最 ...

  3. 粒子群(pso)算法详解matlab代码,粒子群(pso)算法详解matlab代码

    粒子群(pso)算法详解matlab代码 (1)---- 一.粒子群算法的历史 粒子群算法源于复杂适应系统(Complex Adaptive System,CAS).CAS理论于1994年正式提出,C ...

  4. 数学建模——主成分分析算法详解Python代码

    数学建模--主成分分析算法详解Python代码 import matplotlib.pyplot as plt #加载matplotlib用于数据的可视化 from sklearn.decomposi ...

  5. Go-AES算法详解与代码

    目录 AES 发展史 概述 轮函数F 字节代换 行移位 列混淆 轮密钥加 密钥编排 AES和DES的不同之处 分组模式CTR AES的Go实现 aes包 cipher包 加密/解密 参考 本篇介绍分组 ...

  6. 【分享实录】BANCOR算法详解及代码实现

    1 活动基本信息 1)主题:[区块链技术工坊22期]BANCOR算法详解及代码实现 2)议题: BANCOR算法的特点和优劣势 BANCOR算法和举例 如何加入BANCOR.NETWORK交易所 如何 ...

  7. 技术工坊|BANCOR算法详解及代码实现(上海)

    2019独角兽企业重金招聘Python工程师标准>>> EOS项目在RAM分配中采用了Bancor算法,并将RAM的价格爆炒到了很高的价位,凭借EOS项目在区块链领域的强大运营宣传能 ...

  8. 【区块链技术工坊22期实录】王登辉:BANCOR算法详解及代码实现

    1,活动基本信息 1)题目: [区块链技术工坊22期]BANCOR算法详解及代码实现 2)议题: 1)BANCOR算法的特点和优劣势 2)BANCOR算法和举例 3)如何加入BANCOR.NETWOR ...

  9. 算法 经典的八大排序算法详解和代码实现

    算法 经典的八大排序算法详解和代码实现 排序算法的介绍 排序的分类 算法的时间复杂度 时间频度 示例 图表理解时间复杂度的特点 时间复杂度 常见的时间复杂度 空间复杂度 排序算法的时间复杂度 冒泡排序 ...

  10. [联邦学习] FedAvg聚合算法详解及代码实现

    该文章首发于若绾 [联邦学习] FedAvg聚合算法详解及代码实现,转载请标注出处. 论文原文:Communication-Efficient Learning of Deep Networks fr ...

最新文章

  1. oracle 10g安装
  2. MAC下载Linux Centos镜像文件
  3. java中Runnable和Callable的区别
  4. ArcGIS 10.6 Data Interoperability Tools的安装与使用(附安装包下载)
  5. stm32编程入门_电子设计与单片机编程书籍资料推荐
  6. 牛客 13822 Keep In Line(枚举与暴力、Python)
  7. 写了人生中第一个完整模块的用例
  8. 函数:使用数组名作为函数参数进行操作
  9. 为什么我们需要域?MS Active Directory系列之一
  10. 用php写圣诞祝福页面,圣诞祝福文案 抖音圣诞节一句话祝福
  11. 解决在编程方式下无法访问Spark Master问题
  12. wifi 性能 测试 android,WiFi性能测试
  13. 软文外链-软文外链发布软件-软文外链发布工具
  14. 台式计算机m.2的参数,【联想启天 M参数】联想启天 M系列台式电脑参数-ZOL中关村在线...
  15. 论频谱中负频率的物理意义
  16. 英语不规则动词变化时态变化表
  17. C++将一个无效参数传递给了将无效参数视为严重错误的函数
  18. 二叉树前中后序遍历的非递归实现以及层次遍历、zig-zag型遍历详解
  19. python作业_python小作业
  20. 零基础学浙大翁恺C语言(2):计算

热门文章

  1. GRE over IPSec 主备双链路冗余配置
  2. android 仿站小工具,仿站小工具下载
  3. Win10系统优化工具
  4. iphone抓包调试神器—Stream安装和使用
  5. oracle 11g varchar/varchar2
  6. 【C 语言】文件操作 ( 使用 fseek 函数生成指定大小文件 | 偏移量 文件字节数 - 1 )
  7. 两节锂电池保护IC,芯片电路图如何设计
  8. 银行科技岗位 笔试 专业方向重点 + 面试一般问题
  9. java子网掩码计算器_java 子网掩码计算
  10. wowza流媒体服务器最详细教程-wowza安装配置及优化