A*搜寻算法俗称A星算法。这是一种在图形平面上,有多个节点的路径。求出最低通过成本的算法。经常使用于游戏中的NPC的移动计算,或线上游戏的BOT的移动计算上。
这样的算法的所获得的路径并不一定是最短路径但一定是我们所关注的某一方面价值最“优”的路径。我们将地图划分为一个个节点,从出发点到目标的路径就能够使用一个节点列表来表示。
那么怎样获得的这个节点列表才算是“最优”呢?这就要用到我们前面提到的启示式函数,详细表示启示式函数例如以下:
F(p) = G(p) + H(p)
当中F值表示对象从起点经过当前节点p到达目标节点估计总消耗值,G值表示对象从起点到达当前节点p时须要消耗值,H值则表示对象从当前节点p估计到达目标节点须要消耗值。这里须要说明的是,H值是一个估价值,是对象从p点到目标点时,对我们关心的属性定义依照既定计算方式的一种消耗估计,不考虑障碍。能够用棋盘格距离度量,所以这个值并不一定准确。仅仅是起到一个预期的评价。我的理解是H的作用是起到指引作用。指导下次搜索的方向尽可能向目标靠近。当我们对H值得估算给出不同的计算方案时。经过A星得到的路径优势点也就不同。可能是最短路径。也可能是最节省资金的路径……总之就是我们关心的这一属性上消耗最小的一条路径。
#include "stdafx.h" #include<vector> #include<set> #include<algorithm> #include<iostream> using namespace std; #define N 10 #define STARPOINT 1 #define ENDPOINT 2 #define BARRIER 3 #define ROAD 0 //数组中1代表起点,2代表终点,0代表能够通过,3代表障碍物 int landscape[N][N] = { { 1, 0, 0, 3, 0, 3, 0, 0, 0, 0 }, { 0, 0, 3, 0, 0, 0, 0, 3, 0, 3 }, { 3, 0, 0, 0, 0, 3, 3, 3, 0, 3 }, { 3, 0, 3, 0, 0, 3, 0, 2, 0, 3 }, { 3, 0, 0, 0, 0, 3, 0, 0, 0, 3 }, { 3, 0, 0, 3, 0, 0, 3, 3, 0, 3 }, { 3, 0, 0, 0, 0, 3, 3, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 3, 3, 3, 0, 0, 3, 0, 3, 0, 3 }, { 3, 0, 0, 0, 0, 3, 3, 3, 0, 3 }, }; set<pair<int, int>>close_table; pair<int, int>endpoint(3, 7); vector<pair<int, int>>path; bool UDless(pair<pair<int, int>, int> elem1, pair<pair<int, int>, int> elem2) { return elem1.second > elem2.second; } vector<pair<pair<int, int>, int>>get_opentable(pair<int,int>current_point) { vector<pair<pair<int, int>, int>>ve; if (current_point.first - 1 >= 0 && current_point.second - 1 >= 0 && landscape[current_point.first - 1][current_point.second - 1] != BARRIER &&close_table.find(pair<int, int>(current_point.first - 1, current_point.second - 1) )== close_table.end()) { int k = abs(endpoint.first - current_point.first + 1) + abs(endpoint.second - current_point.second + 1)+14; pair<pair<int, int>, int>cc(pair<int, int>(current_point.first - 1, current_point.second - 1), k); ve.push_back(cc);//左上 } if (current_point.first - 1 >= 0 && landscape[current_point.first - 1][current_point.second] != BARRIER && close_table.find(pair<int, int>(current_point.first - 1, current_point.second)) == close_table.end()) { int k = abs(endpoint.first - current_point.first + 1) + abs(endpoint.second - current_point.second)+10; pair<pair<int, int>, int>cc(pair<int, int>(current_point.first - 1, current_point.second), k); ve.push_back(cc);//正上 } if (current_point.first - 1 >= 0 && current_point.second + 1 <N&& landscape[current_point.first - 1][current_point.second + 1] != BARRIER && close_table.find(pair<int, int>(current_point.first - 1, current_point.second + 1)) == close_table.end()) { int k = abs(endpoint.first - current_point.first + 1) + abs(endpoint.second - current_point.second - 1)+14; pair<pair<int, int>, int>cc(pair<int, int>(current_point.first - 1, current_point.second + 1), k); ve.push_back(cc);//右上 } if (current_point.second + 1 < N&& landscape[current_point.first][current_point.second + 1] != BARRIER && close_table.find(pair<int, int>(current_point.first, current_point.second + 1)) == close_table.end()) { int k = abs(endpoint.first - current_point.first) + abs(endpoint.second - current_point.second-1)+10; pair<pair<int, int>, int>cc(pair<int, int>(current_point.first, current_point.second+1), k); ve.push_back(cc);//正右 } if (current_point.first + 1 <N && current_point.second + 1 <N&& landscape[current_point.first + 1][current_point.second + 1] != BARRIER && close_table.find(pair<int, int>(current_point.first+1, current_point.second + 1)) == close_table.end()) { int k = abs(endpoint.first - current_point.first - 1) + abs(endpoint.second - current_point.second - 1) + 14; pair<pair<int, int>, int>cc(pair<int, int>(current_point.first +1, current_point.second + 1), k); ve.push_back(cc);//右下 } if (current_point.first + 1 <N && landscape[current_point.first + 1][current_point.second] != BARRIER && close_table.find(pair<int, int>(current_point.first + 1, current_point.second)) == close_table.end()) { int k = abs(endpoint.first - current_point.first - 1) + abs(endpoint.second - current_point.second ) + 10; pair<pair<int, int>, int>cc(pair<int, int>(current_point.first + 1, current_point.second), k); ve.push_back(cc);//正下 } if (current_point.first + 1 <N && current_point.second - 1 >= 0 && landscape[current_point.first + 1][current_point.second - 1] != BARRIER && close_table.find(pair<int, int>(current_point.first + 1, current_point.second - 1)) == close_table.end()) { int k = abs(endpoint.first - current_point.first - 1) + abs(endpoint.second - current_point.second + 1) + 14; pair<pair<int, int>, int>cc(pair<int, int>(current_point.first +1, current_point.second - 1), k); ve.push_back(cc);//左下 } if (current_point.second - 1 >= 0 && landscape[current_point.first][current_point.second - 1] != BARRIER && close_table.find(pair<int, int>(current_point.first , current_point.second - 1)) == close_table.end()) { int k = abs(endpoint.first - current_point.first ) + abs(endpoint.second - current_point.second + 1) + 10; pair<pair<int, int>, int>cc(pair<int, int>(current_point.first, current_point.second - 1), k); ve.push_back(cc);//正左 } sort(ve.begin(), ve.end(), UDless); return ve; } bool A_star_search(pair<int,int>startpoint) { path.push_back(startpoint); close_table.insert(path.back()); vector<pair<pair<int, int>, int>>open_table; vector<vector<pair<pair<int, int>, int>>>aa; open_table = get_opentable(startpoint); if (open_table.empty()) return false; path.push_back(open_table.back().first); close_table.insert(path.back()); open_table.pop_back(); aa.push_back(open_table); while (!aa.empty()) { open_table = get_opentable(path.back()); if (!open_table.empty()) { path.push_back((open_table.back()).first); close_table.insert(path.back()); vector<pair<pair<int, int>, int>>::iterator it; for (it = open_table.begin(); it != open_table.end(); it++) if (landscape[(*it).first.first][(*it).first.second] == ENDPOINT) { path.push_back(endpoint); return true; } open_table.pop_back(); aa.push_back(open_table); } if (open_table.empty()) { while ((aa.back()).empty()) { close_table.erase(path.back()); path.pop_back(); aa.pop_back(); if (aa.empty()) return false; } close_table.erase(path.back()); path.pop_back(); path.push_back(aa.back().back().first); close_table.insert(path.back()); aa.back().pop_back(); } } } int _tmain(int argc, _TCHAR* argv[]) { vector<pair<int, int>>::iterator it; if (A_star_search(pair<int, int>(0, 0))) for (it = path.begin(); it != path.end(); it++) cout << "(" << (*it).first << "," << (*it).second << ")" << endl; system("pause"); return 0; }
这是一个简易版本号,不保证路径最短。后面我会实现一个最短路径的版本号。