高效的寻路算法—Astar算法(附C++代码)

A*(A-Star)算法是一种静态路网中求解最短路最有效的方法,俗称A星算法。这是一种在图形平面上,有多个节点的路径,求出最低通过成本的算法。常用于游戏中的NPC的移动计算,或线上游戏的BOT的移动计算上。公式表示为:f(n)=g(n)+h(n),其中f(n)是节点n从初始点到目标点的估价函数,g(n)是在状态空间中从初始节点到n节点的实际代价,h(n)是从n到目标节点最佳路径的估计代价。

A-star算法的原理

节点(Node):每个格子都可以称为节点。

代价(Cost):描述角色移动到某个节点时所走的距离(或难易程度)。

对于“曼哈顿算法”,,笔直的走,然后转个弯,再笔直的继续。

“几何算法”的最好解释就是“勾股定理”,算出起点与终点之间的直线距离,然后乘上代价因子。

“对角算法”综合了以上二种算法,先按对角线走,一直走到与终点水平或垂直平行后,再笔直的走。

若以当前单元格为起点(称为父单元格,它的周围有八个方向),下一步走哪呢?

这时就得给下一步的单元格(称为子单元格)进行“估价”。

“估价”可用估价函数来实现。

入门级的估价函数是这样的:

终点到目前点的估计代价=终点至当前点的直线距离

于是下一步的代价可以这样算

代价=起点到当前点的实际步数(通过一个变量累加可以直接得到)+终点到目前点的估计代价

然后把估价后的单元格放入“待考察表”

从待考察表中取代价最小的单元格作为起点,对它周围8个方向的单元格进行估价,然后把它放入“已考察表”。

若对一个单元格估价时,发现它已经在“待考察表”中则比较该单元格原先的估价和当前的估价,保留小的估价,并更新其父单元格属性。

不断重复以上过程,直到在“待考察表”中取出的单元格是终点单元格为止,若“待考察表为空”则表示找不到路径。

到达终点单元格后,通过其“父单元格”属性,一直找到起点,便构成一条路径。

两个例子:

Enterthemap'sfilename:b.txtRows=7Cols=13...................x.........xxxx............x.........xxxx............x...................Setthestartpoint(x,y):53Settheendpoint(x,y):123Steps:12,311,210,19,08,07,06,05,04,03,12,23,34,35,3Rows=7Cols=13....******......*..x...*....*xxxx....*....***x.....*...xxxx............x...................===========================Enterthemap'sfilename:a.txtRows=7Cols=7........xxx......x.x....x.x......x......x......x.Setthestartpoint(x,y):00Settheendpoint(x,y):66Steps:6,66,56,46,36,25,14,03,02,01,00,0Rows=7Cols=7*****...xxx.*....x.x*...x.x*.....x*.....x*.....x*

C++代码

以当前状态下各将牌到目标位置的距离之和作为节点的评价标准。距离的定义为:“某将牌行下标与目标位置行下标之差的绝对值+列下标与目标位置列下标之差的绝对值”。距离越小,该节点的效果越好。某个状态所有将牌到目标位置的距离之和用“h值”表示。

2.1countH(state&st);

countH函数功能是计算st状态的h值。

计算过程中将会用到rightPos数组,数组里记录的是目标状态下,0~9每个将牌在九宫格里的位置(位置=行下标*3+列下标)。

2.2f(state*p);

f()=h()+level

2.3look_up_dup(vector&vec,state*p);

在open表或close表中,是否存在指定状态p,当找到与p完全相等的节点时,退出函数。

2.4search(state&start);

在open表不为空时,按f值由小到大对open表中元素进行排序。

调用findZero()函数找到0值元素的位置。空格可以向上下左右四个方向移动,前提是移动后不能越过九宫格的边界线。确定某方向可走后,空格移动一步,生成状态p’。

此时,检查open表中是否已有p’,若有,更新p’数据;检查close表中是否已有p’,若有,将p’从close表中删除,添加到open表中。重复的执行这个过程,直到某状态的h值为零。

2.5dump_solution(state*q);

在终端输出解路径。

//A*算法八数码问题

#include"stdafx.h"

#include

#include

#include

#include

usingnamespacestd;

constintGRID=3;//Grid表示表格的行数(列数),这是3*3的九宫格

intrightPos[9]={4,0,1,2,5,8,7,6,3};//目标状态时,若p[i][j]=OMG,那么3*i+j=rightPos[OMG]

structstate{

intpanel[GRID][GRID];intlevel;//记录深度inth;

state*parent;

state(intlevel):level(level){}

booloperator==(state&q){

//判断两个状态是否完全相等(对应位置元素相等),完全相等返回true,否则返回false

for(inti=0;i

if(panel[i][j]!=q.panel[i][j])returnfalse;}}

returntrue;}

state&operator=(state&p){//以状态p为当前状态赋值,对应位置元素相同

for(inti=0;i

return*this;}};

voiddump_panel(state*p){//将八数码按3*3矩阵形式输出for(inti=0;i

cout<panel[i][j]<<"";cout<

intcountH(state&st){//给定状态st,计算它的h值。

inth=0;

for(inti=0;i

h+=abs(rightPos[st.panel[i][j]]/GRID-i)+

abs(rightPos[st.panel[i][j]]%GRID-j);

//h=各个将牌与其目标位置的距离之和.距离定义为:行下标之差的绝对值+列下标之差的绝对值。}}

returnh;}

intfindZero(state&st){//找到零值元素,返回其在表中的位置

for(inti=0;i

intf(state*p){//计算并返回f()值,即h值+levelreturncountH(*p)+p->level;}

boolcompare_state(state*p,state*q){//比较两个状态的f值returnf(p)>f(q);}

vectoropen_table;//open表vectorclose_table;//close表

vector::iteratorlook_up_dup(vector&vec,state*p){vector::iteratorit_r=vec.begin();for(;it_r

returnit_r;}

state*search(state&start){//A*算法进行搜索

intlevel=0;

open_table.push_back(&start);intcount=0;

while(!open_table.empty()){

sort(open_table.begin(),open_table.end(),compare_state);//对open表中的元素进行排序

state*p=open_table.back();open_table.pop_back();

if(countH(*p)==0)

returnp;//所有将牌到达目标位置,搜索过程结束level=p->level+1;

intzeroPos=findZero(*p);

intx=zeroPos/3;//空格的行下标inty=zeroPos%3;//空格的列下标

for(inti=0;i<4;i++){//上下左右四个方向intx_offset=0,y_offset=0;switch(i){

case0:x_offset=0,y_offset=1;break;//右case1:x_offset=0,y_offset=-1;break;//左case2:x_offset=1,y_offset=0;break;//上case3:x_offset=-1,y_offset=0;break;//下};

if(x+x_offset<0||x+x_offset>=GRID||y+y_offset<0||y+y_offset>=GRID){continue;

//若移动一步后,将超出上/下/左/右边界,则这个方向不可走,尝试下一个方向

}

state*q=newstate(level);//这个方向可走,扩展下一个节点

q->parent=p;*q=*p;

q->panel[x][y]=q->panel[x+x_offset][y+y_offset];q->panel[x+x_offset][y+y_offset]=0;//空格沿这个方向移一步

boolskip=false;

vector::iteratordup=look_up_dup(open_table,q);//若q已在open表中,则对open表中的信息进行更新

if(dup!=open_table.end()){if(f(q)

(*dup)->level=q->level;(*dup)->parent=q->parent;}

skip=true;}

dup=look_up_dup(close_table,q);

if(dup!=close_table.end()){//若q已在close表中,且f值比原值小,

if(f(q)

delete*dup;

close_table.erase(dup);open_table.push_back(q);skip=true;}}

if(!skip){

open_table.push_back(q);}}

close_table.push_back(p);}}

voiddump_solution(state*q)//输出解路径{

vectortrace;while(q){

trace.push_back(q);q=q->parent;}

intcount=0;

while(!trace.empty()){

cout<<"Step"<

dump_panel(trace.back());

cout<<"h:"<

<

intmain(){

statep(0);state*q;

p.panel[0][0]=2;//设置初始状态p.panel[0][1]=1;p.panel[0][2]=6;p.panel[1][0]=4;p.panel[1][1]=0;p.panel[1][2]=8;p.panel[2][0]=7;p.panel[2][1]=5;p.panel[2][2]=3;

THE END
1.A星算法详解(个人认为最详细,最通俗易懂的一个版本)虽然掌握了 A*算法的人认为它容易,但是对于初学者来说, A* 算法还是很复杂的。 搜索区域(The Search Area) 我们假设某人要从 A 点移动到 B 点,但是这两点之间被一堵墙隔开。如图 1 ,绿色是 A ,红色是 B ,中间蓝色是墙。 图1 你应该注意到了,我们把要搜寻的区域划分成了正方形的格子。这是寻路的第一https://blog.csdn.net/hitwhylz/article/details/23089415
2.A算法详细介绍.pptA*算法 尚福华 A算法 在图搜索算法中,如果能在搜索的每一步都利用估价函数f(n)=g(n)+h(n)对Open表中的节点进行排序,则该搜索算法为A算法。由于估价函数中带有问题自身的启发性信息,因此,A算法又称为启发式搜索算法。 对启发式搜索算法,又可根据搜索过程中选择扩展节点的范围,将其分为全局择优搜索算法和https://max.book118.com/html/2020/0212/5302011221002221.shtm
3.排列组合a的计算方法排列组合中的排列a,其计算公式是高中数学中的一个重要内容。排列数A(n,m)表示从n个不同元素中取出m个元素的所有排列的个数。 排列a的计算公式有两种形式: 直接相乘形式:A(n,m) = n × (n-1) × × (n-m+1) 这个公式表示,从n个元素中选择第一个元素有n种方法,选择第二个元素时剩下n-1种https://agents.baidu.com/content/question/f6702df348a15f3173183c28
4.排列组合a怎么算排列组合A(n,m)=n×(n-1),(n-m+1)=n!/(n-m)!。n为下标,m为上标。排列组合是组合学最基本的概念。所谓排列,就是指从给定个数的元素中取出指定个数的元素进行排序。组合则是指从给定个数的元素中仅仅取出指定个数的元素,不考虑排序。 排列组合的中心问题是研究给定要求的排列和组合可能出现的情况总数https://edu.iask.sina.com.cn/bdjx/6dwQYamJ1ks.html
5.A*算法图文详解A*算法最早于1964年在IEEE Transactions on Systems Science and Cybernetics中的论文《A Formal Basis for the Heuristic Determination of Minimum Cost Paths》中首次提出。 其属于一种经典的启发式搜索方法,所谓启发式搜索,就在于当前搜索结点往下选择下一步结点时,可以通过一个启发函数https://mp.weixin.qq.com/s?__biz=MzU0NjgzMDIxMQ==&mid=2247613871&idx=4&sn=566d8caed79774e4ae02ebd027d25a50&chksm=fb54df43cc235655297bc278ee29f68750adc5cdf3a68512e9597f7e88fd1aefc1f1a0cd87ed&scene=27
6.人工智能A*算法原理A算法是启发式算法重要的一种,主要是用于在两点之间选择一个最优路径,而A的实现也是通过一个估值函数 F=G+H G表示该点到起始点位所需要的代价 H表示该点到终点的曼哈顿距离。 F就是G和H的总和,而最优路径也就是选择最小的F值,进行下一步移动(后边会做详细介绍) https://www.jianshu.com/p/274bbb6598df
7.自动驾驶路径规划:A*(Astar)算法3D视觉工坊最佳优先搜索(BFS),又称A算法,是一种启发式搜索算法(Heuristic Algorithm)。[不是广度优先搜索算法( Breadth First Search , BFS )] BFS算法在广度优先搜索的基础上,用启发估价函数对将要被遍历到的点进行估价,然后选择代价小的进行遍历,直到找到目标节点或者遍历完所有点,算法结束。 https://www.shangyexinzhi.com/article/7063887.html
8.图解A*算法相比于传统的深度搜索和广度搜索的递归回溯算法,A*算法启发式的提供代价估算能力来评估到达目标结点的最短路径所需的代价,即到达终点最省体力的方式。这在我们日常地图导航需求中得到了广泛的应用。本小节我们将以图解的方式向大伙儿揭示A星(这里姑且用星来代指*)算法的奥秘。 https://www.nowcoder.com/discuss/512892732843503616
9.自动驾驶路径规划:A*(Astar)算法最佳优先搜索(BFS),又称A算法,是一种启发式搜索算法(Heuristic Algorithm)。[不是广度优先搜索算法( Breadth First Search , BFS )]BFS算法在广度优先搜索的基础上,用启发估价函数对将要被遍历到的点进行估价,然后选择代价小的进行遍历,直到找到目标节点或者遍历完所有点,算法结束。要实现最佳优先搜索我们必须使用一https://www.elecfans.com/d/2042130.html
10.数据挖掘之Apriori算法详解和Python实现代码分享python这篇文章主要介绍了数据挖掘之Apriori算法详解和Python实现代码分享,本文先是对Apriori算法做了详细介绍,然后给出了Python版实现代码,需要的朋友可以参考下 关联规则挖掘(Association rule mining)是数据挖掘中最活跃的研究方法之一,可以用来发现事情之间的联系,最早是为了发现超市交易数据库中不同的商品之间的关系。(啤酒https://www.jb51.net/article/57209.htm
11.基于A*的双向预处理改进搜索算法摘要:本文针对传统A*算法存在冗余路径点较多与单向搜索耗时较长的缺点, 提出了一种改进A*算法. 该算法采用双向预处理结构减少冗余节点数, 并通过归一化处理和增加节点标记信息进一步优化估价函数提高遍历速度. 利用仿真软件对改进A*算法进行实验, 并与其它经典路径规划算法进行比较. 仿真结果表明, 改进后的A*算法较于https://c-s-a.org.cn/html/2019/5/6923.html
12.基于A*与DWA算法的混合路径规划算法研究为使移动机器人能在各种环境中高效工作, 需要根据实际的地形选择合适的路径规划算法。 为此, 使用A* 与 DWA(Dynamic Window Approach)算法结合的混合路径规划算法, 在仿真环境下搭建 U 型、 S 型、 L 型、狭窄通道型 4 种典型地形进行寻路实验, 同时改进了建图的权重递归公式消除对前一时刻数据依赖, 提高了算http://xuebao.jlu.edu.cn/xxb/CN/abstract/abstract1452.shtml
13.A*算法是怎么做到避开障碍物的?A*算法的理论公式可表示为:f?(n)=g?(n)+h?(n)其中:f?(n)是从初始状态经由状态n到https://www.zhihu.com/question/51626331/answer/2456365853