图论中最短路径的求解之A*算法实现
利用A*算法找到从A城市到B城市的最短路径,以及代价,其中A *算法中的h也就是从当前点到目标点的距离已经给出。程序要有通用性,即其中城市A、B可以为下图中任意的两个城市
在做这个作业时我感觉数据给的不完整,说真的二维图论搜索基本是上按照两点之间的距离作为启发式函数,数据里只给了其他点到一个点直线距离,所以如果城市增多,那么我的这个启发式函数就可能不适用
A*算法简介
假设此时起始点是A,中间点是B,目的地点是C
有三个参数
- h是启发式函数,在本题里面表示无视所有障碍,B到C的距离,一般是直线距离
- g表示cost,也就是A到B走的距离,这个不能无视障碍
- f总的路径长,对于B来说他的f就是 g + h g+h g+h
有两个容器
- openList,经过中心点向四周辐射,将可到达的点放入到openList中,并且按照f,h的大小顺序进行排序,下一次选择中心点就选择f最小的,如果f一样小,就选择h最小的,因为h小的话代价就会小
- closeList,上面我们每一次都选择f、h最小的f小优先作为新的中心点,那么这个点就可以从openList中删除了,然后加入到closeList中,这个容器类似于visit[]数组,就是用来做标记的。但是他的功能不仅于此,还可以通过closeList来回溯出从起始点到终点的路径
启发式函数设计
由于没有给出来所有点之间的直线距离,所以就将两城市到Bucharest的直线的距离的差的绝对值作为启发式函数
//采用起始点和终点到B城市的直线距离的差的绝对值用来做H
int getH(int start, int end) {
return abs(strai_dist_B[start] - strai_dist_B[end]);
}
具体实现
数据结构:
- 定义一个结构体Node表示每一个节点,id表示着城市的序号,father_id表示他之前点的序号
struct Node{
int f;
int g;
int h;
int id; //城市的序号
int father_id;
Node() {
f = 0;
g = 0;
h = 0;
id = -1;
father_id = -1;
}
Node(int g, int h, int id, int father_id){
this->h = h;
this->g = g;
this->id = id;
this->f = g+h;
this->father_id = father_id;
}
};
一共有三个大步骤
首先我们要将起始点加入到openList中,这个不算三步里面。
-
对openList进行排序,排序的规则是最小原则,f优先于h。找出来最小的节点,并且将其设定为中心点,然后将改点从openLIst中删除,并且加入到clsoeList中。
//这个是排序函数,肯定是先排f较小的 //如果出现f相等了,那么就看他们的h,如果h越小,那么说明离的越近 bool cmp(const Node& node1, const Node &node2) { if(node1.f < node2.f) return true; else if(node1.f > node2.f) return false; else { if(node1.h < node2.h) return true; } return false; }
-
从中心点开始遍历周围可以到达的点。在这一题里面就是找到临近的城市
-
-
临近城市、不在closeList中
-
如果不在openList中,就加入到openList,并且将father_id设置为中心节点的序号
-
如果在openList中,需要判断B点(假设这个点是B,中心点是A)是否需要进行更新。更新的原则就是:
if(dist[A.id][B.id] + A.g < B.g): B.g = dist[A.id][B.id] + A.g B.father.id = A.id
此时整个openList需要进行从新排序
-
- 如果终点在了openList中,那么这个算法就可以停止了,如果最后openLIst空了,那么就搜索失败了
上述三步代码如下
运行截图
后记
这个是我的人工智能课的题目,之前一直在网上搜查资料,在求最短路径中,他们对于A * 算法的实现基本不对,主要还是没有更新openList,写下这篇博客最主要的原因还是,我的某个傻屌同学一直不承认他写的不是A * 算法,我理论不过,遂写下这篇博客。当然了如果存在问题,可以评论我