码迷,mamicode.com
首页 > 其他好文 > 详细

[知识点]A*搜索(启发式搜索)

时间:2015-07-27 00:11:49      阅读:225      评论:0      收藏:0      [点我收藏+]

标签:

// 此博文为迁移而来,写于2015年4月4日,不代表本人现在的观点与看法。原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vwud.html

 

1、前言
       树一般的搜索多为DFS和BFS。A*算法,其实说得简单一点,就是聪明些;说复杂些,A*算法的前途和作用是非常大的——他甚至要涉及到人工智能(AI)。所以,A*是很有前途的。
 
2、概念
       A*同样是以BFS为框架进行搜索的。其实就是加强版的BFS。。他需要定义一个函数,设为H(x),称作估价函数。估价函数的定义有很多种形式。先举一个很简单的例子:
技术分享 // 标准图已丢失
       定义一个直角坐标系,S为起点,T为终点。中间深蓝色的地方为不可移动的高地。我们先来分析一下使用DFS或BFS的效率:从S开始,它需要遍历整个地图,可见是很慢的。在这种情况下,用A*搜索绝对是快一些的,但是A*必须将估价函数定义得足够合理。下面具体介绍估价函数。
 
3、估价函数
       搜索时,对于距离的定义普遍可以表示为:
 
        F=G+H   (G为搜索时起点到该点的深度,H为估价函数)
 
       在上图中,用到的方法称为Manhattan method(曼哈顿距离),就是从考虑的点通过水平和垂直移动达到目标点的移动步数。注意只是水平和垂直移动,不走斜线。并且忽略图中的障碍物。
-----------------------------------------------------------------------------------------------------
int getVal(int x,int y,int dep) { return (abs(x-tx)+abs(y-ty)+dep); } // abs为绝对值
-----------------------------------------------------------------------------------------------------
       注意,不是所有A*搜索的估价函数是一样的,比如“八数码难题”、“靶形数独”所需的估价函数都是不一样的!而且,这里只介绍最普通的估价函数,具体题目要具体分析,需要自己一步一步去试最合适的估价函数。
 
4、搜索
       根据上述估价函数,可以得到目前的状态:
技术分享// 标准图已丢失

       初始化的时候,我们将节点S保存在一个数组(其使用普通的数组是不行的,后面会讲如何实现)。节点S开始搜索周围8个节点,得到F值。本轮搜索结束。下一轮的时候,将所有还没有向下遍历的节点(即之前已经保存的节点)中找出F值最小的,记为minNode,将minNode从数组里删除。
技术分享

       从minNode开始继续搜索,得到更多的节点保存。反复搜索,直到数组里没有任何节点(注意!搜到了终点不能直接退出!想一想,为什么),搜索结束。
 
 
5、存储及遍历的方式
       如上所述,数组很明显是不行的。我们需要先开一个结构体,用以保存每个节点的x,y,val,dep。val记录F值。
遍历的时候,可以看出,需要使用队列进行出队入队。但是,每次我们需要找到的节点是F值最小的啊!而不是先进先出。所以,之前所提到的“堆”(http://blog.sina.com.cn/s/blog_6022c4720102vss0.html)就有作用啦,而不是只能进行堆排序。堆,在这里其实用它另一个名字更加合适——优先队列。每次,我们从队列中选出F值最小的,很容易就实现了。为了“标新立异”,在Cab的带领下,我用了系统优先队列(这是我第一次用STL中的数据结构。。。。)
-----------------------------------------------------------------------------------------------------
priority_queue<node,vector<node>,cmp> q; 
-----------------------------------------------------------------------------------------------------
       这是优先队列的定义方式,需要queue库,vector库。这里用的是结构体优先队列,之间的“vector<node>”是默认的格式,具体的原因我也不知道。。反正就这么打就可以了,如果需要定义整型的优先队列,把node改成int就行了。cmp就是优先队列比较方式,要自己写,类似于sort(str+1,str+n+1,cmp)。使用方式类似于普通的队列,具体的自己查吧。。。我觉得挺好理解的。STL就是有各种局限。
 
6、代码
       最简单的直角坐标系跑最短路。输入0-1地图以及起点终点。求出需要走多少步。
-----------------------------------------------------------------------------------------------------
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<cstdlib>
#define INF 1<<30
#define MAXN 1005
using namespace std;
 
struct node
{
  int x,y,val,dep,dist;
  node () { }
  node (int a, int b) { x=a; y=b; }
};
node path[MAXN];
 
struct cmp // 比较方式
{
  bool operator () (node a,node b)
  {
    return (a.val>b.val);
  }
};
 
int sx,sy,tx,ty,nx,ny,map[MAXN][MAXN];
priority_queue<node,vector<node>,cmp> q;
 
int n,s,t,x[MAXN],y[MAXN],now;
 
int abs(int a) { return (a<0)?-a:a; }
 
int getVal(int x,int y,int dep) { return (abs(x-tx)+abs(y-ty)+dep); }
 
int getMan(int x,int y) { return (abs(x-sx)+abs(y-sy)); } 
 
int check(int x,int y)
{
  return ( x>0 && y>0 && x<=map[nx][ny]);
}
 
void BFS()
{
  node s=node(sx,sy); s.dep=0; s.dist=0;
  q.push(s);
  while (q.empty()!=1)
  {
    node minNode=q.top();
    nx=minNode.x; ny=minNode.y;
    if (minNode.x==tx && minNode.y==ty)
    {
      printf("%d",minNode.dist);
      exit(0);
    }
    q.pop();
    if (check(nx,ny+1)==1)
    {
      node temp=node(nx,ny+1);
      temp.dep=getMan(nx,ny+1);
      temp.val=getVal(nx,ny+1,temp.dep);
      temp.dist=minNode.dist+1;
      map[nx][ny+1]=temp.dep;
      q.push(temp);
    }
    if (check(nx,ny-1)==1)
    {
      node temp=node(nx,ny-1);
      temp.dep=getMan(nx,ny-1);
      temp.val=getVal(nx,ny-1,temp.dep);
      temp.dist=minNode.dist+1;
      map[nx][ny-1]=temp.dep;
      q.push(temp);
    }
    if (check(nx+1,ny)==1)
    {
      node temp=node(nx+1,ny);
      temp.dep=getMan(nx+1,ny);
      temp.val=getVal(nx+1,ny,temp.dep);
      temp.dist=minNode.dist+1;
      map[nx+1][ny]=temp.dep;
      q.push(temp);
    }
    if (check(nx-1,ny)==1)
    {
      node temp=node(nx-1,ny);
      temp.dep=getMan(nx-1,ny);
      temp.val=getVal(nx-1,ny,temp.dep);
      temp.dist=minNode.dist+1;
      map[nx-1][ny]=temp.dep;
      q.push(temp);
    }
  }
}
 
void init()
{
  freopen("AStar.in","r",stdin);
  freopen("AStar.out","w",stdout);
  scanf("%d",&n);
  for (int i=1;i<=n;i++)
  for (int j=1;j<=n;j++) { scanf("%d",&map[i][j]); if (map[i][j]==1) map[i][j]=INF; }
  scanf("%d %d %d %d",&sx,&sy,&tx,&ty);
}
 
int main()
{
  init();
  BFS();
  return 0;
}
-----------------------------------------------------------------------------------------------------

[知识点]A*搜索(启发式搜索)

标签:

原文地址:http://www.cnblogs.com/jinkun113/p/4678852.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!