前言:
(好好看完哦,后面有惊喜~~)
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;
}
展示:
好了,相信大家已经仔细看完了,下面我提供给大家一个网站,可以清楚的明白各种搜索算法的搜索路径。
传送门:
动画展示各种路径搜索算法