[C++]:A*——A Star演算法簡介
A*演算法 求最優解
演算法一直維護兩個表: Open和Close
- 將起點S加入Open中
- 將所有S可到達的點(障礙物以及位於Close表中的點均看成不可達)加入到Open中。將起點從Open中刪去,並加入到Close中
- ①從Open中刪去F值最小的點Min,並將其加入到Close中
- ②將Min點所有可到達的點加入Open中,並設這些點的父節點為Min。若某點已經在Open中,則比較其F值,若新路徑F值較小,說明從Min走路更短,更新其父節點為Min;否則不更新此點
- 迴圈①②,直到Open中出現目的點E
公式表示為: f(n)=g(n)+h(n),
其中 f(n) 是從初始狀態經由狀態n到目標狀態的代價估計,
g(n) 是在狀態空間中從初始狀態到狀態n的實際代價,
h(n) 是從狀態n到目標狀態的最佳路徑的估計代價。
通俗一點講:
g(n)代表你從起始點到下一點的實際距離(制定到下一點的距離的規則)
h(n)是自己設計的函式,可以是到目的地大致的距離
可將迴圈過程封裝成函式:
while (isNotEnd()) {
Find_deleteMinFromOpen_AddToClose();
putReachableIntoOpen(close.back());
}
舉個栗子:
對於以下圖:5行15列
000000000000000
0000000x0000000
00s0000x0000e00
0000000x0000000
000000000000000
其中x為牆壁,s為起點,e為終點,建立合適的模型,呼叫A star演算法,找到一條s到e的最短路徑。
取直走G值為10,斜走G值為14
這裡H值設定為無視障礙到達終點所需的 步數*10
我們看開始的幾步:
000000000000000
0000000x0000000
00s0000x0000e00
0000000x0000000
000000000000000
灰色的點G=10,H=9*10 ,其F值最小,加入Close
000000000000000
0000000x0000000
00s0000x0000e00
0000000x0000000
000000000000000
灰色的點G=10+10,H=8*10 ,其F值最小,加入Close
000000000000000
0000000x0000000
00s0000x0000e00
0000000x0000000
000000000000000
灰色的點G=10+10+10,H=7*10 ,其F值最小,加入Close
000000000000000
0000000x0000000
00s0000x0000e00
0000000x0000000
000000000000000
灰色的點G=10+10+10+10,H=6*10 ,其F值最小,加入Close
以此迴圈,直到e在Open中,此時只需要沿著父節點往回走就可以到達起點了,這條路就是當前情況下最優的解
結果:
000000000000000
0000000x0000000
00s0000x0000e00
0000000x0000000
000000000000000
C++實現:
#include#include#include#includeusing namespace std; char square[5][15] = {//待求資料 '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', '0','0','0','0','0','0','0','x','0','0','0','0','0','0','0', '0','0','s','0','0','0','0','x','0','0','0','0','e','0','0', '0','0','0','0','0','0','0','x','0','0','0','0','0','0','0', '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0' }; class point { public: point(char s) { v = s; G = 0; H = 0; F = 0; } pair ParentPosi; pair posi; char v;//value int F; int G; int H; int UpdateF() { F = G + H; return F; } int UpdateH() { int x = posi.first - 2; int y = posi.second - 12; x *= 10; y *= 10; if (x < 0) { x = -x; } if (y < 0) { y = -y; } H = x + y; return H; } void setPosi(pair x) { posi = x; } void setParentPosi(pair x) { ParentPosi= x; } void setG(int g) { G = g; } void setH(int h) { H = h; } point &operator = (point &s) { (*this).v=(s).v; (*this).ParentPosi = s.ParentPosi; (*this).posi = s.posi; (*this).F = s.F; (*this).G = s.G; (*this).H = s.H; return *this; } }; vector open; vector close; point squ[5][15] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,'x',0,0,0,0,0,0,0, 0,0,'s',0,0,0,0,'x',0,0,0,0,'e',0,0, 0,0,0,0,0,0,0,'x',0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; bool isInOpenList(pair s) { for (int i = 0;i<open.size();i++) { if (open[i].posi == s) { return true; } } return false; } bool isInCloseList(pair s) { for (int i = 0;i<close.size();i++) { if (close[i].posi == s) { return true; } } return false; } void putReachableIntoOpen(point min) { int x = min.posi.first; int y = min.posi.second; int direc[8][2] = { 0,1, 1,1, 1,0, 1,-1, 0,-1, -1,-1, -1,0, -1,1 }; for (int i = 0;i < 8;i++) { x = x + direc[i][0]; y = y + direc[i][1]; if (isInOpenList(make_pair(x, y))&&close.size()>0) { int tempi = 0; for (int i = 0;i < open.size();i++) { if (open[i].posi == make_pair(x, y)) { tempi = i; } } if (direc[i][0] * direc[i][1] != 0) {//斜向 int G_now = close.back().G + 14; if (G_now < open[tempi].G) { //G比較小就更新路徑 open[tempi].ParentPosi = make_pair(x, y); squ[open[tempi].posi.first][open[tempi].posi.second].ParentPosi = make_pair(x, y); } } else { int G_now = close.back().G + 10; } continue; } //既不在關閉也不在開啟列表中而且可到達 就將其加入開啟列表 if ((!isInOpenList(make_pair(x, y))) && (!isInCloseList(make_pair(x,y)))&&x >= 0 && x < 5 && square[x][y] != 'x') { squ[x][y].setParentPosi(min.posi); open.push_back(squ[x][y]); if (direc[i][0] * direc[i][1] != 0) {//斜向 squ[x][y].setG(squ[x][y].G+14); } else { squ[x][y].setG(squ[x][y].G + 10); } //cout << "(" << squ[x][y].posi.first << "," << squ[x][y].posi.second << ")" << endl; } x = x - direc[i][0]; y = y - direc[i][1]; } //cout << "------------------------" << "(" << x << "," << y << "):" << "------------------------" << endl; } void Find_deleteMinFromOpen_AddToClose() { point min_= open[0]; int tempi = 0; for (int i = 0;i < open.size();i++) { if (open[i].UpdateF() < min_.UpdateF()) { min_ = open[i]; tempi = i; } } close.push_back(min_); std::vector::iterator it=open.begin()+tempi; open.erase(it); //cout << "close: (" << min_.posi.first << "," << min_.posi.second << ")" << endl; //cout << "closeSize()=" << close.size() << endl; //cout << "openSize()=" << open.size() << endl; } bool isNotEnd() { for (int i=0;i<open.size();i++) { if (open[i].v == 'e') { open[i].ParentPosi=close.back().posi; return false; } } return true; } void findPath(pair begin,pairend) { //將起點放入open open.push_back(squ[2][2]); putReachableIntoOpen(squ[2][2]); int tempi = 0; for (int i = 0;i < open.size();i++) { if (open[i].v == 's') { tempi = i; } } std::vector::iterator it = open.begin()+tempi;//刪除起點 while (isNotEnd()) { Find_deleteMinFromOpen_AddToClose(); putReachableIntoOpen(close.back()); } } void print_path() { for (int i = 0;i < 5;i++) { for (int j = 0;j < 15;j++) { squ[i][j].posi = make_pair(i, j); squ[i][j].UpdateH();//算出所有H } }//初始化point.posi findPath(make_pair(2,2),make_pair(2,12)); point temp = squ[2][12]; vector<pair> point_out; while (temp.posi!=squ[2][2].posi) { //cout << "(" << temp.posi.first << "," << temp.posi.second << ")" << endl; point_out.push_back(temp.posi); temp=squ[temp.ParentPosi.first][temp.ParentPosi.second]; } point_out.push_back(squ[2][2].posi); while (point_out.size() != 0) { cout << "(" << point_out.back().first<< "," << point_out.back().second<< ")" << endl; point_out.pop_back(); } } void print() { for (int i = 0;i < 5;i++) { for (int j = 0;j < 15;j++) { cout << square[i][j] << ' '; } cout << endl; } } int main() { //print(); print_path(); return 0; }