A*寻路算法

前言:

(好好看完哦,后面有惊喜~~)
A寻路算法在游戏和导航等软件中广泛应用。
A
寻路算法是一种启发性寻路算法,是一种高效的寻路算法。

题解:

A*寻路算法的思想:
启发性搜索:公式:f=g+h;
用来衡量效率的一个数字:代价小(距离短),代价大(距离远)。
f:当前点到终点的代价
g:起点到当前点的代价
h:当前点到终点的预估代价

因为我们可以走直线也可以走斜线,所以我们定义走直线的代价为10,走斜线的代价为14(≈10倍的根号2)所以我们就可以算出g了。
下面我们来算h:
h点是当前点到终点的预估代价,我们再这里忽略障碍,只算当前点到终点的直线距离(横向距离+纵向距离)。
下面我们用图的例子来解释一下:
红色格子代表起点,蓝色格子代表终点,褐色格子代表障碍物,红色格子一圈格子的上面数字代表h值,下面格子代表g值。f=g+h,我们在这一圈格子中选择f值最小的格子,即为下一步要到的点。我们如此每次前进一步,直至到达终点。(当然我们在走的时候肯定是要判断是否能走,具体的详见代码)。
在这里插入图片描述
算法的思想已经大概说完了,由于代码中的注释足够详细,我在这里就不一一介绍代码的每一步的含义了,下面详见代码。

代码1:

#include<iostream>
#include<cmath>
#include<vector>
using namespace std;
#define ROW 12   //行
#define COL 12   //列
struct Mypoint
{
	int x;
	int y;
	int f;
	int g;
	int h;
};
struct MyMap {
	int value;
	bool visited;
};
struct treeNode
{
	Mypoint pos;    //当前点
	treeNode* parent;  //树节点
	vector<treeNode*> chilred;  //子节点
};
bool canWalk(Mypoint pos, MyMap mymap[ROW][COL])
{
	if (pos.x < 0 || pos.x >= ROW || pos.y < 0 || pos.y >= COL)//不在地图范围内
	{
		return false;
	}
	if (mymap[pos.x][pos.y].value == 1)//是障碍不能走
	{
		return false;
	}
	if (mymap[pos.x][pos.y].visited == true)//已经走过了不能走
	{
		return false;
	}
	return true;
}
int main()
{
	int map[ROW][COL] = {   //地图
		{0,0,0,0,1,0,0,0,0,0,0,0},
		{0,0,1,1,1,0,0,0,0,0,0,0},
		{0,1,0,1,1,0,0,0,0,0,0,0},
		{0,0,1,0,1,0,0,0,0,0,0,0},
		{0,0,1,1,1,0,0,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0,0,0},
		{0,0,0,0,0,0,0,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0,0,0}
	};
	Mypoint beginPos = { 1,1 };//起点坐标
	Mypoint endPos = { 5,10 };  //终点坐标
	MyMap mymap[ROW][COL];//辅助地图
	int i, j;
	for (i = 0; i < 12; i++)  //初始化辅助地图
	{
		for (j = 0; j < 12; j++)
		{
			mymap[i][j].value = map[i][j];
			mymap[i][j].visited = false;
		}
	}
	//创建一棵树
	treeNode* pRoot = NULL;
	//标记起点走过
	mymap[beginPos.x][beginPos.y].visited = true;

	//起点入树,成为根节点
	pRoot = new treeNode;
	pRoot->pos = beginPos;
	pRoot->parent = NULL;
	//准备一个数组用来保存所有的评估点
	vector<treeNode*> temp;
	;
	//寻路
	//Mypoint currentPos = beginPos; //当前点
	treeNode* ptemp = pRoot;  //当前树节点
	bool isfindend = false;  //当等于true时意味着走到终点结束
	while (1)
	{
		//检查当前点周围那些点要纳入评估
		for (i = ptemp->pos.x - 1; i <= ptemp->pos.x + 1; i++)
		{
			for (j = ptemp->pos.y - 1; j <= ptemp->pos.y + 1; j++)
			{
				if (i == ptemp->pos.x && j == ptemp->pos.y)
				{
					continue;
				}
				else
				{
					treeNode* pchild = new treeNode;
					Mypoint temp1;
					temp1.x = i;
					temp1.y = j;
					if (abs(i - ptemp->pos.x) == 1 && abs(j - ptemp->pos.y) == 1)
					{
						temp1.g = ptemp->pos.g+14;
					}
					else
					{
						temp1.g = ptemp->pos.g+10;
					}
					temp1.h = abs(i - endPos.x) * 10 + abs(j - endPos.y) * 10;
					temp1.f = temp1.g + temp1.h;     //计算所有评估点的f值
					pchild->pos = temp1;
					if (canWalk(pchild->pos, mymap))
					{
						ptemp->chilred.push_back(pchild);
						pchild->parent = ptemp;
						temp.push_back(pchild);
						//cout << "(" << pchild->pos.x << "," << pchild->pos.y << ")"<<endl ;
					}
				}
			}
		}
		//找出f值最小的一个点,走!并从temp中删除这个点
		int min = temp[0]->pos.f;
		int min_x = temp[0]->pos.x;
		int min_y = temp[0]->pos.y;
		int pos=0;
		for (i = 1; i < temp.size(); i++)
		{
			if (temp[i]->pos.f < min)
			{
				min = temp[i]->pos.f;
				min_x = temp[i]->pos.x;
				min_y = temp[i]->pos.y;
				pos = i;
			}
		}
		ptemp = temp[pos];//走
		mymap[ptemp->pos.x][ptemp->pos.y].visited = true;
		temp.erase(temp.begin() + pos);
		//判断是否找到终点,判断是否整个地图都找我还是没找到终点
		if (ptemp->pos.x == endPos.x && ptemp->pos.y == endPos.y)
		{
			isfindend = true;
			break;
		}
		if (temp.empty())
		{
			//cout << "1" << endl;
			break;
		}
	}
	//打印路径
	if (isfindend)
	{
		cout << "找到终点了!!!" << endl;
		while (ptemp)
		{
			cout << "(" << ptemp->pos.x << "," << ptemp->pos.y << ")" << endl;
			ptemp = ptemp->parent;
		}
	}
	else
	{
		cout << "没有一条路径" << endl;
	}
	return 0;
}

代码2:

#include<iostream>
#include<vector>
#define ROW 12
#define COL 12
using namespace std;
struct point
{
	int x;
	int y;
	int f;
	int g;
	int h;
	point* parent;
};
point* find_min(vector<point*> open)//从开放列表找出f最小的节点
{
	point* temp = open[0];
	int min = open[0]->f;
	int i;
	for (i = 1; i < open.size(); i++)
	{
		if (open[i]->f < min)
		{
			min = open[i]->f;
			temp = open[i];
		}
	}
	return temp;
}
bool hasin(point* a, vector<point*> close)//查找close列表中是否有当前节点
{
	int i;
	for (i = 0; i < close.size(); i++)
	{
		if (close[i]->x == a->x&&close[i]->y==a->y)
		{
			return true;
		}
	}
	return false;
}
void Erase(point* a, vector<point*>& open)
{
	vector <point*>::iterator iter=open.begin();
	//cout << open.size() << endl;
	while (iter != open.end())
	{
		if (*iter == a)
		{
			open.erase(iter);
		//	cout << "true" << endl;
		//	cout << open.size() << endl;
			break;
		}
		iter++;
	}
}
bool canwalk(int map[ROW][COL], point* temp, vector<point*> close)
{
	if (temp->x < 0 || temp->x >= ROW || temp->y < 0 || temp->y >= COL)//越界,不能走
	{
		return false;
	}
	if (map[temp->x][temp->y] == 1)//是障碍物,不能走
	{
		return false;
	}
	if (hasin(temp, close))//已经走过了,不能走
	{
		return false;
	}
	return true;
}
int main()
{
	int map[ROW][COL] = {   //地图
		{0,0,0,0,1,0,0,0,0,0,0,0},
		{0,0,1,1,1,0,0,0,0,0,0,0},
		{0,1,0,1,1,0,0,0,0,0,0,0},
		{0,0,1,0,1,0,0,0,0,0,0,0},
		{0,0,1,1,1,0,0,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0,0,0},
		{0,0,0,0,1,1,1,1,1,1,1,0},
		{0,0,0,0,1,0,0,0,0,0,0,0},
		{0,0,0,0,0,0,0,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0,0,0}
	};
	point beginPos;//起点坐标
	beginPos.x = 1;
	beginPos.y = 1;
	beginPos.f = 1000;
	point endPos;  //终点坐标
	endPos.x = 1;
	endPos.y = 10;
	point *cur = &beginPos;
	cur->parent = NULL;
	int i, j;
	vector<point*> open;//打开列表
	vector<point*> close;//关闭列表
	bool isfind = false;//判断是否找到终点
	open.push_back(cur);
	while (!open.empty())//当打开列表为空时,意味着地图上所有点都访问过
	{
		cur = find_min(open);//找到打开列表中f值最小的节点
		if (cur->x == endPos.x && cur->y == endPos.y)//到达终点时
		{
			isfind = true;
			break;
		}
		Erase(cur, open);//把当前的节点从打开列表中删除
		close.push_back(cur);//把当前节点送人关闭列表
		for (i = cur->x - 1; i <= cur->x + 1; i++)//计算当前节点周围可走点的f值
		{
			for (j = cur->y - 1; j <= cur->y + 1; j++)
			{
				if (i == cur->x && j == cur->y)
				{
					continue;
				}
				else
				{
					point* temp = new point;
					temp->x = i;
					temp->y = j;
					if (abs(i - cur->x) == 1 && abs(j - cur->y) == 1)//计算g值
					{
						temp->g = cur->g+14;
					}
					else
					{
						temp->g = cur->g+10;
					}
					temp->h= abs(i - endPos.x) * 10 + abs(j - endPos.y) * 10;//计算h值
					temp->f = temp->g + temp->h;//计算f值
					if (canwalk(map, temp, close))
					{
						if (!hasin(temp, open))//当前节点没在打开列表中,就拉入
						{
							temp->parent = cur;
							open.push_back(temp);
						}
						else
						{
							for (int k = 0; k < open.size(); k++)//当前节点在打开列表中
							{
								if (temp->x == open[k]->x && temp->y == open[k]->y&&temp->g<open[k]->g)//如果当前的g值小于打开列表中该点的g值,则更新之
								{
									open[k]->g = temp->g;
									break;
								}
							}
						}
					}
				}
			}
		}
	}
	if (isfind)//找到终点
	{
		int sum = -1;
		cout << "找到终点了!!!   从终点到起点的路径为:" << endl;
		while (cur)
		{
			cout << "(" << cur->x<< "," << cur->y << ")" << endl;
			cur = cur->parent;
			sum++;
		}
		cout << "一共需要走" << sum << "步" << endl;
	}
	else//没找到终点
	{
		cout << "找不到该路径" << endl;
	}
	return 0;
}

展示:

在这里插入图片描述

好了,相信大家已经仔细看完了,下面我提供给大家一个网站,可以清楚的明白各种搜索算法的搜索路径。
传送门:
动画展示各种路径搜索算法

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值