Astar的自我学习

Astar的自我学习

最近进行了搜索的一系列自学,自然少不了Astar。
在这个学习过程中有一些其他的东西,所以也附在这篇文章里。(如果有什么不好的地方,望大家提出,以便作者的改进,谢谢。)


优先队列

优先队列就是一个被赋予了优先级的队列,按照重载函数进行最大值或最小值优先。在出队和提取队首元素时都是按照优先级来操作,优先级最大的元素将进行操作。

#include<cstdio>
#include<queue>
#include<ctime>
#include<algorithm>
using namespace std;
struct node
{
    int x,y;
}a[10];
struct cmp
{
    bool operator()(node &a,node &b)//注意结构体队列时这里也要改为结构体
    {  
        return a.x<b.x;//最大值优先  
    }  
};
priority_queue <node,vector<node>,cmp> q;//优先队列的定义
int main()
{
    srand(time(NULL));
    for(int i=0;i<10;i++)
    {
        a[i].x=rand()%101,a[i].y=rand()%101;//随机数的产生
        q.push(a[i]);
    }
    while(!q.empty())
    {
        node t=q.top();
        printf("%d %d\n",t.x,t.y);//要新开一个结构体(上行)来进行输出
        q.pop();
    }
}

这个只是一个优先队列的示范,如果运行这个程序将会随机生成100以内的数入队,在出队时的顺序按照每个元素的x的大小进行。而在Astar算法中的优先顺序将以f的大小进行。

Astar算法

这种搜索算法又被称为启发式搜索,其中的启发的估价函数可以这样表示 f(n) = g(n) + h(n)
g是起点到当前位置的消耗,h是当前位置到终点的消耗。
此算法中有一个开启队列和一个结束队列,在我的程序中我用bool数组进行判断,在一个节点已经进行过操作那么这个节点就应该在结束队列里,并且把它从开启队列中删去。并且我的估计函数十分的简单(也因为是测试题目中没有权值)仅仅是计算起点和终点到这个点的步数而已,但也能体现出算法的思想。
来一个简单的题目:
输入n,m。是行和列,地图中1表示障碍,0表示可以通过。在这之后输入起点和终点的横,纵坐标,输出起点到终点的最短路径。
代码如下(有不足之处请见谅):

#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<algorithm>
using namespace std;
int map[105][105];
//结构体定义
struct v
{
    int f,g,h,x,y;
}vis[105][105];
struct g
{
    int x,y;
}dad[105][105];
//重载函数
struct cmp
{
    bool operator()(v &a,v &b)
    {  
        return a.f>b.f;
    }  
};
priority_queue <v,vector<v>,cmp> open;
bool close[105][105],open_check[105][105];
g s;
g e;
int n,m;
int f[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
//估价函数
void Valuation(int x,int y,int x1,int y2)
{
    vis[x][y].h=abs((e.y-y)+(e.x-x));
    vis[x][y].g=vis[x1][y2].g+1;
    vis[x][y].f=vis[x][y].g+vis[x][y].h;
}
//回溯打印路径
void Print(int x,int y)
{
    if(x==s.x&&y==s.y)
    {
        printf("(%d,%d)\n",x,y);
        return ;
    }
    Print(dad[x][y].x,dad[x][y].y);
    printf("(%d,%d)\n",x,y);
}
//Astar算法
void AStar(int x,int y)
{
    v lit;
    lit.x=x; lit.y=y;
    open_check[lit.x][lit.y]=1;
    open.push(lit);//将起点入队
    while(!open.empty())
    {
        v t=open.top();
        open.pop(); close[t.x][t.y]=1; open_check[t.x][t.y]=0;//在开启队列中关闭,在结束队列中开启
        if(t.x==e.x&&t.y==e.y)//当前节点是终点
        {
            Print(e.x,e.y);
            exit(0);
        }
        for(int i=0;i<4;i++)
        {
            v news;
            news.x=t.x+f[i][0];
            news.y=t.y+f[i][1];
            if(news.x<1||news.y<1||news.x>n||news.y>m||close[news.x][news.y]||map[news.x][news.y])//判断是否超出地图,是否是障碍,是否在结束队列了
                continue;
            if(vis[news.x][news.y].g&&t.g+1>vis[news.x][news.y].g)//如果新节点的g小于当前的g,更新父节点
            {
                dad[t.x][t.y].x=news.x;
                dad[t.x][t.y].y=news.y;
            }
            else
            {
                Valuation(news.x,news.y,t.x,t.y);
                dad[news.x][news.y].x=t.x;
                dad[news.x][news.y].y=t.y;
            }
            news.f=vis[news.x][news.y].f;
            news.g=vis[news.x][news.y].g;
            news.h=vis[news.x][news.y].h;
            if(!open_check[news.x][news.y])//不在开启队列就入队
            {
                open.push(news);
                open_check[news.x][news.y]=1;
            }
        }
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&map[i][j]);
    scanf("%d%d%d%d",&s.x,&s.y,&e.x,&e.y);
    AStar(s.x,s.y);
}

如有不足之处,请见谅并评论告知,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值