A*算法
本质还是搜索:加了优化而已
关于这个优化,听到两种说法:
1.剪枝
通过判断预计最少还要几步,加强版剪枝
比如说一个经典剪枝:
如果
步数≥已知最小值
则
剪枝
升级|
V
如果
步数+最少还要几步≥已知最小值
则
剪枝
2.修改顺序
每次搜索时优先考虑最有可能是最有解的选项
(启发的感觉)
可以建个优先队列来维护每次取到的f最小
注:
f=g+h
g为已经用的步数
h为预计要用的步数
——我倾向于这一种,因为感觉更加神奇,而且写出来是非递归(递归的心理阴影)——
下面来一道水题:BFS轻松过的我来写A*
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19699poj3984事实上既然m n都是5,BFS说不定会比A*更优
但是说明问题就好
1 #include <cstdio> 2 #include <queue> 3 #include <cmath> 4 using namespace std; 5 struct hh 6 { 7 int x,y,z; 8 }; 9 priority_queue<hh> q; 10 int n,m,t,x1,yy,x2,y2,_x,_y; 11 bool ma[101][101],b[101][101],c[101][101]; 12 int f[101][101],g[101][101],h[101][101],fa[101][101],mo[101][101]; 13 bool operator <(hh a,hh b) 14 { 15 return a.z>b.z; 16 } 17 int add(int x,int y,int z) 18 { 19 hh p; 20 p.x=y;p.y=z;p.z=x; 21 q.push(p); 22 return 0; 23 } 24 int check(int x,int y,int z,int ff,int m) 25 { 26 if(!ma[x][y]) 27 { 28 if(b[x][y]) 29 { 30 if(g[x][y]>z) 31 { 32 g[x][y]=z; 33 f[x][y]=z+h[x][y]; 34 fa[x][y]=ff; 35 mo[x][y]=m; 36 add(f[x][y],x,y); 37 } 38 } 39 else 40 if(!c[x][y]) 41 { 42 b[x][y]=true; 43 g[x][y]=z; 44 h[x][y]=abs(x-x2)+abs(y-y2); 45 f[x][y]=g[x][y]+h[x][y]; 46 fa[x][y]=ff; 47 mo[x][y]=m; 48 add(f[x][y],x,y); 49 } 50 } 51 return 0; 52 } 53 int a_star() 54 { 55 check(x1,yy,0,0,0); 56 while(!q.empty()) 57 { 58 int x=q.top().x; 59 int y=q.top().y; 60 q.pop(); 61 if((x==x2)&&(y==y2)) 62 return g[x][y]; 63 b[x][y]=false; 64 c[x][y]=true; 65 check(x-1,y,g[x][y]+1,x,y); 66 check(x,y-1,g[x][y]+1,x,y); 67 check(x+1,y,g[x][y]+1,x,y); 68 check(x,y+1,g[x][y]+1,x,y); 69 } 70 return 0; 71 } 72 int print(int x,int y) 73 { 74 if(fa[x][y]>0) 75 print(fa[x][y],mo[x][y]); 76 printf("(%d, %d) ",x-1,y-1); 77 return 0; 78 } 79 int main() 80 { 81 n=5;m=5; 82 for(int i=1;i<=n;i++) 83 for(int j=1;j<=m;j++) 84 scanf("%d",&ma[i][j]); 85 x1=1;yy=1;x2=5;y2=5; 86 a_star(); 87 print(5,5); 88 return 0; 89 }
代码不是很长,而且因为刚写完别的题,这里只是套了一下,很多代码是多余的
print递归输出不用管
a_star是主要程序(一看就知道)
check用于检查当前点周围一圈的点能不能加入队列,b表示点是否已经加入,c表示该点是否已经退出(已退出的不用管了)
记得在有更优值时更新
其实像是一种更加神奇的Dj——优先级是预计中的全路而不是已搜到的路,让程序能稍稍有点远见前面是坑还是会钻
这样写最神奇的地方在于它会向着目标一头栽过去,而不是像广搜只顾着预定的顺序,更加接近正常人的逻辑,因此搜索范围大大减小。
既然每个点都只能进队列一次,这个算法的复杂度最差情况下还是很低的