!!(5月27日)发现一个很牛的东东,可以加深理解A* http://qiao.github.io/PathFinding.js/visual/
去年的这个时候和同学一起玩code vs asia的比赛学会了A*算法
当初在数据结构算法什么都不懂的情况下,我们能写出A*算法已经感觉非常满足了
当初用java进行实现的,那个时候脑袋里就只想着能实现就好,于是那个神奇的A*就被我们迷迷糊糊的写出来了
下面就想着高兴呢,也没仔细想过整体的流程,那里可以有优化的地方。虽然整体实现了,但是细节方面简直是令人发指
时隔一年,玩acm再次碰到了那个相似的使用A*算法的情况。于是凭借着我寥寥无几的数据结构知识外加蹩脚的c,c++语言使用
写出了一个自我感觉比以前java实现的优化了那么一点点的A*算法
接下来正题:
如果你清楚A*算法但是不知道怎么实现,我这里可能稍微给你一点帮助
如果你不清楚A*算法,可以先去学一下,网络上有很多比较好的文章,这里我就不多做讲解了
A*堆优化方式:A*算法利用了一个估价函数,计算图上节点的时候,对节点进行了整体的估价
然后选出最优的节点进行访问,以此类推...
既然是选择最优的节点,那么我们就可以实现一个优先队列。来方便我们取出最优的节点。所以使用堆就成了我们优化的不二选择
把能访问的节点加入我们的开放队列(堆形式),取出F最小的节点,然后访问与这个节点相连的节点,并且把满足条件能访问的加入
开放列表,如果满足条件并且已经加入到开放列表中了,那么就比较其G值。选取比较小的,然后更新开放列表中的节点。
(这里,在使用以维护F的最小值为条件的堆中,我们无法快速判断一个节点是否已经存在于堆中。所以我想到了另外再构建一个hash图
维护原图的每一个节点在堆中的位置,这样就能使用hash图直接的判断原图中的节点是否已经存在于堆中。维护hash图,需要和维护堆进行同步
所以每次加入一个节点时维护hash图的复杂度为logN,同维护堆的logN,并且在判断的时候是O(1)的时间复杂度,但构建hash图又增加了空间复杂度)
(优化好处,比A*算法使用普通链表形式进行维护的开放列表时间复杂度上好很多,普通链表取最小值,打擂台形式,时间复杂度O(N),插入的时候
判断有没有已经被插入也是O(N),所以比较时间复杂度优点显而易见)
下面是我憋脚的实现。
测试的图为二维的平面图,可以上下左右,四个方向行走,也可以八个方向行走(八个方向少考虑一个问题),图上0表示可以走,1表示不通。
八方向少考虑的问题是:如果图为00 那么我能否从(1,1)直接走到(2,2)也就是斜角过能否“蹩马脚”
10
额,打字好累直接贴代码好了
#include
#include
#define MAX 500
static int DX[8]= {-1,0,1,0,1,-1,1,-1};
static int DY[8]= {0,1,0,-1,1,1,-1,-1};
int grap[MAX][MAX];
int hash[MAX][MAX];
int n,m;
struct Node {
int x,y,g,h,f;
};
Node heap[MAX*MAX];
int h_end=0;
int insert(Node n);//堆中插入节点
int update(int idx,Node n);//向上更新堆中的节点
Node getMin();//取出堆中的最小值
void swap(int idx1,int idx2);//交换hash数组对应堆中节点的位置,并交换堆中的节点
void add_open(int x,int y,int g,Node e,int dir);//把图上的节点添加进开放列表
void add_close(Node n);//把图上的节点添加进关闭列表
void aStar(Node s,Node e,int dir);//主要算法
int insert(Node n) {
return update(++h_end,n);
}
int update(int idx,Node n) {
int e=idx,p;
heap[e]=n;
while(e>1) {
p=e>>1;
if(heap[e].fh_end||rs>h_end) {
if(ls<=h_end&&heap[rt].f>heap[ls].f)swap(rt,ls);
break;
}
if(heap[rt].f<=heap[ls].f&&heap[rt].f<=heap[rs].f)break;
if(heap[rt].f>heap[ls].f&&heap[rs].f>=heap[ls].f) {
swap(rt,ls);
rt=ls;
} else {
swap(rt,rs);
rt=rs;
}
}
return res;
}
void swap(int idx1,int idx2) {
hash[heap[idx1].x][heap[idx1].y]=idx2;
hash[heap[idx2].x][heap[idx2].y]=idx1;
Node tmp=heap[idx1];
heap[idx1]=heap[idx2];
heap[idx2]=tmp;
}
void add_open(int x,int y,int g,Node e,int dir) {
if(x<0||x>=n)return;
if(y<0||y>=m)return;
if(grap[x][y]!=0||hash[x][y]==-1)return;
Node tmp;
tmp.x=x;tmp.y=y;
int h;
if(dir<4) {
g=g+10;
h=(abs(e.x-x)+abs(e.y-y))*10;
} else {
g=g+14;
h=(abs(e.x-x)+abs(e.y-y))*10;
}
tmp.g=g;
tmp.h=h;
tmp.f=g+h;
if(hash[x][y]!=0) {
if(heap[hash[x][y]].g>g) {
update(hash[x][y],tmp);
}
} else {
hash[x][y]=insert(tmp);
}
}
void add_close(Node n) {
hash[n.x][n.y]=0;
grap[n.x][n.y]=88;
}
void aStar(Node s,Node e,int dir) {
hash[s.x][s.y]=insert(s);
Node tmp;
int x,y,g,i;
while(h_end>0) {
tmp=getMin();
add_close(tmp);
if(tmp.x==e.x&&tmp.y==e.y) {
printf("%d\n",tmp.g);
break;
}
for(i=0; i