A*搜索就是在BFS的基础上给出到终点更多的信息,约搜索点到终点地信息,使得一个搜索点到终点的距离最短。而且A*算法又有dijkstra的优点他能保持一个点到起始点的距离也是最短,这就能保证能在条件内得出最短距离。而A*中的估算函数对运行时间很重要,对于估算函数有很多种算法,一个点到终点的距离H(u)中的信息越多保证到终点的距离也就越短,但相对的运算时间也就要增加。而一个点到起始点的距离G(u)是确定的,所以函数也是可以确定的。而一个搜索点到起始点的距离加上一个搜索点到终点的距离F(u)=G(u)+H(u)的距离只要最短就能得出最短路径。所以只要在F(u)集中不断找对小权值点就能得到最短路径了。
下面贴代码:
public class Point_ai//存储各个搜索点的信息
{
public Point loc;
public Point_ai father;
int G;
int H;
public int F;
public void min_path(Point start, Point end)
{
//到起点的估计值
this.G = (int)Math.Sqrt(Math.Abs(start.X - loc.X) * Math.Abs(start.X - loc.X) + Math.Abs(start.Y - loc.Y) * Math.Abs(start.Y - loc.Y));
//到终点的估计值
this.H = (int)Math.Sqrt(Math.Abs(end.X - loc.X) * Math.Abs(end.X - loc.X) + Math.Abs(end.Y - loc.Y) * Math.Abs(end.Y - loc.Y));
this.F = this.G + this.H;
}
public Point_ai(Point lo)
{
this.loc = lo;
}
public Point_ai()
{
}
}
public partial class A_star
{
//A*搜索
public List<Point_ai> openlist=new List<Point_ai>();
public List<Point_ai> closelist=new List<Point_ai>();
/* public bool is_colli(Point po)//障碍检测A*搜索中障碍检测要重写这只是贪吃蛇的写法
{
for (int i = 1; i < snakeLen_ai -1; ++i)
{
if (po.X == snakeArr_ai[i].X && po.Y == snakeArr_ai[i].Y)
{
return true;
}
}
if (po.X < 0 || po.X > ClientRectangle.Width || po.Y < 0 || po.Y > ClientRectangle.Height)
{
return true;
}
return false;
}*/
public bool is_inclose(Point lo)//是否在关闭列表 如果关闭列表就说明这个点已经测试过了不需要进行重复测试
{
foreach (Point_ai loc in closelist)
{
if (lo == loc.loc)
{
return true;
}
}
return false;
}
public void add_open(Point_ai loc, Point start, Point end)//加入开启列表
{
/* 这些就是H(u) 的信息 信息越多 得到的距离也就越短 */
/* 这里搜索的就四个方向 如果将搜索的方向增加到8个 也就是全方位搜索那么得出的距离会越短 */
/*在这个贪吃蛇中我们以 15的边长的正方形做搜索的点 */
Point temp = new Point();
temp.X = loc.loc.X + 15;//右
temp.Y = loc.loc.Y;
if (!is_inclose(temp) && !is_colli(temp))
{
Point_ai lo = new Point_ai(temp);
lo.min_path(start, end);
lo.father = loc;//连接父节点 以便得出路劲
openlist.Add(lo);
}
temp.X = loc.loc.X - 15;//左
temp.Y = loc.loc.Y;
if (!is_inclose(temp) && !is_colli(temp))
{
Point_ai lo = new Point_ai(temp);
lo.min_path(start, end);
lo.father = loc;//连接父节点 以便得出路劲
openlist.Add(lo);
}
temp.X = loc.loc.X; //下
temp.Y = loc.loc.Y + 15;
if (!is_inclose(temp) && !is_colli(temp))
{
Point_ai lo = new Point_ai(temp);
lo.min_path(start, end);
lo.father = loc;//连接父节点 以便得出路劲
openlist.Add(lo);
}
temp.X = loc.loc.X; //上
temp.Y = loc.loc.Y - 15;
if (!is_inclose(temp) && !is_colli(temp))
{
Point_ai lo = new Point_ai(temp);
lo.min_path(start, end);
lo.father = loc;//连接父节点 以便得出路劲
openlist.Add(lo);
}
}
public Point_ai search_min()//找开启列表里的最小权
{
int min = 9999999;
Point_ai re = new Point_ai();
for (int i = 0; i < openlist.Count;++i )//搜索开启列表
{
if (!is_inclose(openlist[i].loc))//如果不在关闭列表
{
if (openlist[i].F < min)//找F(u)值最小的点
{
min = openlist[i].F;//更新最小权
re = openlist[i];//更新最小权点
}
}
else
{
openlist.Remove(openlist[i]);//如果已经在关闭列表就移出开启列表
}
}
openlist.Remove(re);//移除已检测点
closelist.Add(re);//加入到关闭列表以防再次搜索
return re;//返回最小权值点
}
public Point A(Point_ai start, Point_ai end)//A*搜索
{
Point_ai min = new Point_ai();
closelist.Add(start);//移除起始点
add_open(start, start.loc, end.loc);//加搜索区域
while (openlist.Count != 0)//如果开启列表不为空
{
min = search_min();//获取开启列表最小F(u)
add_open(min, start.loc, end.loc);//加搜索区域
if (min.loc == end.loc)//如果检测到最小点已经是终点 退出
{
break;
}
}
while (min.father.loc != start.loc)//寻找路径的第一个节点
{
min = min.father;//因为在C#中一切对象皆是引用 所以直接写 如果在C++中要用指针 否则无法赋值
}
openlist.Clear();//清空开启列表
closelist.Clear();//清空关闭列表
return min.loc;//返回第一个节点
}
}