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);
}
如有不足之处,请见谅并评论告知,谢谢。