A*算法求解迷宫

原文地址:http://blog.csdn.net/qq120848369/article/details/5548386

一个求解截图


 

[cpp] view plaincopy
#include <queue>  
#include <vector>  
#include <iostream>  
using namespace std;  
  
//方向向量  
int direc[4][2]={{0,1},{-1,0},{0,-1},{1,0}};  
  
//封闭,开放列表标记  
enum Flag  
{  
    SEAL,  
    OPEN,  
    UNVISITED  
};  
  
//===========最小堆节点类============  
//堆优先级为:F=G+H   
//G为当前的路径长  
//H为估计当前位置到目标位置开销探测:当前节点(x,y),目标节点(x0,y0),则以曼哈顿距离作为H,H=|x-x0|+|y-y0|  
  
typedef struct node  
{  
    int _x,_y;//节点坐标(x,y)  
    int _G;//实际已开销G  
    int _H;//探测将开销H  
    int _F;//优先级_F=_G+_H  
    struct node *pre; //前驱顶点  
}Queue_Node;  
  
//_seal[][]结构体,保存结点的开放(封闭)标记,保存开放结点的指针  
typedef struct  
{  
    Flag flag;  
    Queue_Node *point;  
}Seal;  
  
//=============A*算法类=============  
//类成员列表如下:  
//1.A*算法核心  
//2.计算曼哈顿距离H函数  
//3.迷宫输入函数  
//4.最优解路径输出函数  
//5.封闭列表  
//6.最小堆实现开放列表  
//7.迷宫长,宽  
//8.迷宫地图  
//9.起点,目标点  
//10.最小堆排序函数  
//11.绝对值函数  
//12.边界判断  
//13.打印路径  
class A_Star  
{  
public:  
    //构造函数,打印欢迎信息  
    A_Star()  
    {  
        cout<<"您正在使用的是入门级A*算法求解迷宫"<<endl;  
        cout<<"算法采用广度优先搜索,以及探测方法优先选择开销最小的状态节点进行拓展"<<endl;  
        cout<<"下面,您应该根据提示输入各种迷宫的信息,并请求调用A*算法求解"<<endl;  
        input();  
    }  
    //析构函数  
    ~A_Star()  
    {  
        for(int i=1;i<=_len;++i)  
        {  
            for(int j=1;j<=_wid;++j)  
            {  
                if(_seal[i][j].point!=NULL)  
                {  
                    delete _seal[i][j].point;  
                }  
            }  
        }  
        for(int i=0;i<=_len;++i)  
        {  
            delete []_seal[i];  
            delete []_maze[i];  
        }  
        delete []_seal;  
        delete []_maze;  
    }  
    //迷宫输入函数  
    void input()  
    {  
        cout<<"输入: 迷宫左边长,上边宽! 例如:5 3"<<endl;  
        cin>>_len>>_wid;  
        _seal=new Seal*[_len+1];  
        _maze=new unsigned char*[_len+1];  
        for(int i=0;i<=_len;++i)  
        {  
            _seal[i]=new Seal[_wid+1];  
            _maze[i]=new unsigned char[_wid+1];  
        }  
        cout<<"从下一行开始输入迷宫信息"<<endl;  
        for(int i=1;i<=_len;++i)  
        {  
            for(int j=1;j<=_wid;++j)  
            {  
                cin>>_maze[i][j];  
                _seal[i][j].flag=UNVISITED;  
                _seal[i][j].point=NULL;  
            }  
        }  
        cout<<"输入起点坐标,目标点坐标,例如1 2 3 4"<<endl;  
        cin>>_sx>>_sy>>_ex>>_ey;  
        if(_maze[_sx][_sy]=='1'||_maze[_ex][_ey]=='1'||bound(_sx,_sy)==false||bound(_ex,_ey)==false)  
        {  
            cout<<"不可能存在这样的情况!"<<endl;  
            return;  
        }  
        cout<<"调用A*算法打印结果如下:"<<endl;  
        A();  
    }  
    //A*核心算法  
    void A()  
    {  
        //源点入开放列表  
        Queue_Node *p_node=new Queue_Node;  
        p_node->pre=NULL;  
        p_node->_H=get_H(_sx,_sy);  
        p_node->_G=0;  
        p_node->_x=_sx;  
        p_node->_y=_sy;  
        p_node->_F=p_node->_H+p_node->_G;  
        _open.push(p_node);  
        _seal[_sx][_sy].flag=OPEN;  
        _seal[_sx][_sy].point=p_node;  
        //A*搜索  
        while(!_open.empty())  
        {  
            p_node=_open.top();  
            _open.pop();  
            int x=p_node->_x;  
            int y=p_node->_y;  
            _seal[x][y].flag=SEAL;  
  
            for(int i=0;i<4;++i)  
            {  
                int tx=x+direc[i][0];  
                int ty=y+direc[i][1];  
                if(bound(tx,ty)==false||_maze[tx][ty]=='1'||_seal[tx][ty].flag==SEAL)//边界,无路,封闭,则不考虑这个格  
                {  
                    continue;  
                }  
                if(_seal[tx][ty].flag==UNVISITED)  
                {  
                    if(tx==_ex&&ty==_ey)  
                    {  
                        print(p_node);  
                        cout<<"("<<tx<<","<<ty<<")"<<endl;  
                        cout<<"总共走了:"<<p_node->_F<<"步"<<endl;  
                        return;  
                    }  
                    Queue_Node *temp=new Queue_Node;  
                    _seal[tx][ty].flag=OPEN;  
                    _seal[tx][ty].point=temp;  
                    temp->pre=p_node;  
                    temp->_G=p_node->_G+1;  
                    temp->_x=tx;  
                    temp->_y=ty;  
                    temp->_H=get_H(tx,ty);  
                    temp->_F=temp->_G+temp->_H;  
                    _open.push(temp);  
                }  
                else  
                {  
                    Queue_Node *temp=_seal[tx][ty].point;  
                    if(p_node->_G+1<temp->_G)  
                    {  
                        temp->_G=p_node->_G+1;  
                        temp->pre=p_node;  
                        temp->_F=temp->_G+temp->_H;  
                    }  
                }  
            }  
        }  
        cout<<"没有从("<<_sx<<","<<_sy<<")--->"<<"("<<_ex<<","<<_ey<<")的路径"<<endl;  
    }  
    //打印路径  
    void print(Queue_Node *p)  
    {  
        if(p==NULL)  
        {  
            return;  
        }  
        print(p->pre);  
        cout<<"("<<p->_x<<","<<p->_y<<"),";  
    }  
    //边界判断  
    bool bound(int x,int y)  
    {  
        return (x<=_len)&&(x>=1)&&(y<=_wid)&&(y>=1);  
    }  
    //计算曼哈顿距离H函数  
    int get_H(int x,int y)  
    {  
        return ab(x-_ex)+ab(y-_ey);  
    }  
    //绝对值函数  
    int ab(int i)  
    {  
        return i<0? -i:i;  
    }  
private:  
    //仿比较函数结构体  
    struct cmp  
    {  
        bool operator()(Queue_Node *n1,Queue_Node *n2)  
        {  
            return n1->_F>n2->_F;  
        }  
    };  
    priority_queue<Queue_Node *,vector<Queue_Node *>,cmp> _open;//最小堆(开放列表)  
    int _len,_wid;//迷宫左边长,上边宽  
    int _sx,_sy,_ex,_ey;  
    Seal **_seal;//动态开辟封闭列表  
    unsigned char **_maze;//迷宫地图  
};  
  
  
int main()  
{  
    A_Star test;  
    return 0;  
}  
 

 

A*算法总结

 

1.           将开始节点放入开放列表(开始节点的FG值都视为0);

2.           重复一下步骤:

            i.        在开放列表中查找具有最小F值的节点,并把查找到的节点作为当前节点;

           ii.        当前节点从开放列表删除加入到封闭列表;

         iii.        当前节点相邻的每一个节点依次执行以下步骤:

1.     如果该相邻节点不可通行或者该相邻节点已经在封闭列表中,则什么操作也不执行,继续检验下一个节点;

2.     如果该相邻节点不在开放列表中,则将该节点添加到开放列表中并将该相邻节点的父节点设为当前节点,同时保存该相邻节点GF;

3.     如果该相邻节点在开放列表中则判断若经由当前节点到达该相邻节点G值是否小于原来保存的G,若小于,则将该相邻节点的父节点设为当前节点,并重新设置该相邻节点GF.

        iv.        循环结束条件:

终点节点被加入到开放列表作为待检验节点时表示路径被找到,此时应终止循环;

或者当开放列表为空,表明已无可以添加的新节点,而已检验的节点中没有终点节点则意味着路径无法被找到,此时也结束循环;

3.           终点节点开始沿父节点遍历并保存整个遍历到的节点坐标,遍历所得的节点就是最后得到的路径;

 

 

路径排序

 

决定哪些方格会形成路径的关键是下面这个等式:

F = G + H

这里

·                  G=从起点A沿着已生成的路径到一个给定方格的移动开销。

·                  H
=从给定方格到目的方格的估计移动开销。这种方式常叫做试探,有点困惑人吧。其实之所以叫做试探法是因为这只是一个猜测。在找到路径之前我们实际上并不知
道实际的距离,因为任何东西都有可能出现在半路上(墙啊,水啊什么的)。本文中给出了一种计算H值的方法,网上还有很多其他文章介绍的不同方法。

我们要的路径是通过反复遍历开放列表并选择具有最小F值的方格来生成的.

 

 

重要的是,在计算H值时并不考虑任何障碍物。因为这是对剩余距离的估计值而不是实际值(通常是要保证估计值不大于实际值――译者注)。这就是为什么这个方式被叫做试探
法的原因了。

 

 

主要在于维护开放封闭列表的方式,这里用一个结构体矩阵_seal[][]标记开放或者封闭,如果开放,则point还记录了该格子所对应状态结点的指针,可以方便直接取出该节点修改信息.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值