终于学习了传说中的A*搜索~...
先通俗的说一下A*搜索的原理,然后用代码实现~
A*搜索是在基于广搜的基础上的一种启发式搜索方式(我也不知道启发式是什么意思),可以大大降低搜索时间,找出相对正确的最优路径。
这里用到了特殊的存储结构---优先队列,可以优化将查找的复杂度从O(n)有化成O(logn);
1、首先我们从原点开始进行A*搜索,把原点入队列,然后标记为已访问
2.接收优先队列队列第一个元素并pop掉,判断第一个元素相邻的八个位置,如果其中有的位置是障碍物或者超出地图范围或者已经访问过,则排除,其他位置入栈,并用pre指针指向父节点
3.找出其中相对h+g最优的解(可用优先队列实现),重复2步骤,直到找到终点;
代码实现
#include <iostream> #include <cstdio> #include <queue> #include <cmath> using namespace std; int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}}; struct node { bool visit; int x,y; double hx,gx;//核心 char ch; node *pre; node() { visit = 0; pre = NULL; } }map[51][51],start,end; bool judge(int x, int y) { if(x>=0 && x<=50 && y>=0 && y<=50) return true; else return false; } double Euclidean_dis(int sx,int sy,int ex,int ey){//欧几里德 double nn; nn=sqrt((sx-ex)*(sx-ex)+(sy-ey)*(sy-ey)); return nn; } double Chebyshev_dis(int sx,int sy,int ex,int ey){//切比雪夫 double nn; nn=max(abs(sx-ex),abs(sy-ey)); return nn; } double jiaquan_Manhattan(int sx,int sy,int ex,int ey){//加权曼哈顿 //better double nn,dx,dy; dx=abs(sx-ex); dy=abs(sy-ey); if(dx>dy) nn=10*dx+6*dy; else nn=6*dx+10*dy; return nn; } //重载运算符 bool operator<(node a, node b) { return a.gx + a.hx > b.gx + b.hx; } //寻找路径 void viewback() { node *p; p = map[end.x][end.y].pre; while(p) { if(p->pre) { p->ch = ‘v‘; } p = p->pre; } return; } void Astar() { priority_queue<node> q; q.push(start); int xx,yy; int i; while(!q.empty()) { node now = q.top(); q.pop(); if(now.x==end.x&&now.y == end.y) { break; } for(int i=0; i<4; i++) { xx = now.x + dir[i][0]; yy = now.y + dir[i][1]; if(!judge(xx, yy)||map[xx][yy].ch == ‘x‘ || map[xx][yy].visit == 1) { continue; } map[xx][yy].visit = 1; map[xx][yy].pre = &map[now.x][now.y]; map[xx][yy].hx = jiaquan_Manhattan(xx, yy, end.x, end.y); map[xx][yy].gx = now.gx + 1; q.push(map[xx][yy]); } } return ; } int main() { freopen("t.txt", "r", stdin); int i,j,visi_num=0; for(i=0;i<50;i++){ for(j=0;j<50;j++){ cin>>map[i][j].ch; map[i][j].x=i; map[i][j].y=j; if(map[i][j].ch==‘s‘){ map[i][j].gx=0; map[i][j].visit=1; start=map[i][j]; } if(map[i][j].ch==‘e‘) end=map[i][j]; } getchar(); } cout<<"结果---------------------------------------------------"<<endl; Astar(); viewback(); for(i=0;i<50;i++){ for(j=0;j<50;j++){ visi_num+=map[i][j].visit; if(map[i][j].ch==‘v‘ || map[i][j].ch==‘e‘ || map[i][j].ch==‘s‘) printf("%c",map[i][j].ch); else if(map[i][j].visit) printf("%d",map[i][j].visit); else printf("%c",map[i][j].ch); } cout<<"\n"; } printf("\n遍历节点 %d 个\n",visi_num); return 0; }
这个代码写的很好,我从网上好不容易找到的~...
时间: 2024-10-26 19:40:56