zoukankan      html  css  js  c++  java
  • [旧版][知识点]A*搜索(启发式搜索)

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

    Update - 20200517

    该博文内容现已更新并迁移至:

    [知识点] 3.2 五种改进搜索算法 https://www.cnblogs.com/jinkun113/p/12889652.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地图以及起点终点。求出需要走多少步。
     
      UPDATE(20180805):今天看了一眼,以前写的是什么东西啊。
     
    #include <cstdio>
    #include <queue>
    #include <cstdlib>
    using namespace std;
    
    #define MAXN 105
    #define INF 0x3f3f3f3f
    
    int n, m, a[MAXN][MAXN], sx, sy, tx, ty, ans = INF;
    
    struct node {
        int x, y, w, d;
    };
    
    struct cmp {
        bool operator () (node a, node b) {
            return a.w < b.w;
        }
    };
    
    priority_queue <node, vector<node>, cmp> Q;
    
    int min(int a, int b) {
        return a < b ? a : b; 
    }
    
    int abs(int o) {
        return o > 0 ? o : -o;
    }
    
    int get(int x, int y) {
        return (abs(x - tx) + abs(y - ty));
    }
    
    bool chk(int x, int y) {
        return (x > 0 && y > 0 && x <= n && y <= m && !a[x][y]);
    }
    
    void search() {
        Q.push((node) {sx, sy, get(sx, sy), 0}), a[sx][sy] = 1;
        while (!Q.empty()) {
            node o = Q.top();
            if (o.x == tx && o.y == ty) printf("%d", o.d), exit(0);
            for (int vx = -1; vx <= 1; vx++)
                for (int vy = -1; vy <= 1; vy++)
                    if (vx != 0 || vy != 0) {
                        int nx = o.x + vx, ny = o.y + vy, nd = o.d + 1;
                        if (chk(nx, ny)) Q.push((node) {nx, ny, get(nx, ny) + nd, nd}), a[nx][ny] = 1;
                    }
            Q.pop();
        }
    }
    
    int main() {
        scanf("%d %d", &n, &m);
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++) scanf("%d", &a[i][j]);
        scanf("%d %d %d %d", &sx, &sy, &tx, &ty);
        search();
        return 0;
    } 
  • 相关阅读:
    我的word发布博客测试
    framework源码调试
    微软发布各个阶段的发布程序
    ora9客户端字符集
    现知道一服务器有合法ip,现在在远端应如何连接到这个服务器访问
    布式Oracle的database link
    怎样用delphi7中的SQLconnection组件远程连接Oracle数据库
    不用安装oracle客户端使用oracle
    有关linux下远程连接(转)
    如何限制某个用户只能FTP不能TELNET?
  • 原文地址:https://www.cnblogs.com/jinkun113/p/4678852.html
Copyright © 2011-2022 走看看