①以A星为基础的寻路算法:遗传算法,蚁群算法. . .
②各参数的含义
f :最终做选择的依据、代价-> 用来评价寻路的快慢
g:从起点到当前点已经付出的代价-> 沉没成本
h:当前点到终点的预估代价
③有关沉没成本、预估代价的含义:
沉没成本 g:
小明和小红去创业,小明无工作 0 收入,小红工作每月收入2 W,小明的沉没成本就是 0元 / 月,小红的沉没成本就是 2W / 月,如果去创业,小红就相当于每个月损失2W,小明没有损失
预估代价 h:
假设小明和小红创业的收益分别为:小明1.5W /月,小红3W / 月
最终整合起来:小明去创业更合适,他的整体代价最小
④实际案例:
走一个直线的代价与斜线的代价之比为1:1.414
蓝色部分为 g 值 红色部分为 h 值 紫色部分为最佳路径
⑤需要准备的数据结构
(1)一棵树:记录整个过程中的路线、经过
(2)一个数组buffer:纳入考虑的点要找出来哪一个 f 值最小
(3)三张地图:①地图1MAP是真地图
②地图2是用来判断是否走过的
③地图3是用来判断是否放进过buffer的
⑥遇到死胡同的解决办法:
从起点(树的根节点)开始,每一步都是去找它周围能走的点(指没有走过的点,而非没有加入过buffer的点),然后入树,
(先判断之前是否放过)放到容器buffer中,找完之后,从容器buffer中挑出来 f 值最小的那一个,把它从容器中删掉,让它变成树的当前点,再循环,从当前点开始,找当前点周围能走的点,入树,一路去找. . .
⑦其他算法流程的描述:
此处的open列表就是buffer
⑧H的计算方法:
两种计算方法->本处采用曼哈顿距离
- #include
//有abs - #include
-
- using namespace std;
- #define ROWS 10
- #define COLS 10
-
- #define Direct_Cost 10
- #define Oblique_Cost 14
-
- bool CanWalk(const struct Point& p, bool pathmap[ROWS][COLS], bool MAP[ROWS][COLS]);
- //准备->①辅助地图 ②MAP ③树节点类型 ④坐标类型 ⑤buffer存储已经检测过的点 ⑥方向的枚举类型
- bool pathMap[ROWS][COLS] = { 0 };//0表示没有走过
- bool pathMap_isAddBuff[ROWS][COLS] = { 0 };
- bool MAP[ROWS][COLS] =
- {
- { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 },//0
- { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 },//1
- { 0, 0, 1, 1, 1, 0, 0, 0, 0, 0 },//2
- { 0, 1, 0, 1, 1, 0, 0, 0, 0, 0 },//3
- { 0, 1, 1, 0, 1, 0, 0, 1, 0, 0 },//4
- { 0, 0, 1, 1, 1, 0, 1, 1, 0, 0 },//5
- { 0, 0, 0, 0, 1, 0, 1, 0, 0, 0 },//6
- { 1, 0, 1, 1, 1, 0, 1, 0, 0, 0 },//7
- { 0, 1, 1, 0, 0, 1, 1, 0, 0, 0 },//8
- { 0, 0, 0, 1, 1, 0, 1, 0, 0, 0 }//9
- };
- struct Point
- {
- int row;
- int col;
- int f, g, h;
- bool operator==(const Point& a) { return (row == a.row && col == a.col); }
- void getH(const Point& end);
- void getF() { f = g + h; };
- };
- struct treeNode
- {
- Point data;
- treeNode *pParent;
- vector
pChild; - treeNode() = default;
- treeNode(const Point& d)
- {
- treeNode* pNew = new treeNode;
- pParent = nullptr;
- data = d;
- }
- };
- vector
buffer; - enum dir{UP,RIGHT,DOWN,LEFT,RIGHT_UP,RIGHT_DOWN,LEFT_DOWN,LEFT_UP};
- int main()
- {
- Point begPos = { 0,0 }; //起点和终点
- Point endPos = { 6,7 };
- treeNode *pRoot=new treeNode(begPos);
- pathMap_isAddBuff[pRoot->data.row][pRoot->data.col] = 1;
- bool isFind = false;
- treeNode *pCurrent=pRoot;
- treeNode *pSearch;
-
- while (!isFind)
- {
- for (int i = 0; i < 8; i++)
- {
- pSearch = new treeNode(pCurrent->data);//每次进来都要重置pSearch->切不能修改到pCurrent的data!!!!
- switch (i)
- {
- case UP:pSearch->data.row--; pSearch->data.g += Direct_Cost; break;
- case DOWN:pSearch->data.row++; pSearch->data.g += Direct_Cost; break;
- case RIGHT:pSearch->data.col++; pSearch->data.g += Direct_Cost; break;
- case LEFT:pSearch->data.col--; pSearch->data.g += Direct_Cost; break;
- case RIGHT_DOWN:pSearch->data.row++; pSearch->data.col++; pSearch->data.g += Oblique_Cost; break;
- case RIGHT_UP:pSearch->data.row--; pSearch->data.col++; pSearch->data.g += Oblique_Cost; break;
- case LEFT_DOWN:pSearch->data.row++; pSearch->data.col--; pSearch->data.g += Oblique_Cost; break;
- case LEFT_UP:pSearch->data.row--; pSearch->data.col--; pSearch->data.g += Oblique_Cost; break;
- }
- if (CanWalk(pSearch->data, pathMap, MAP))
- {
- if (pathMap_isAddBuff[pSearch->data.row][pSearch->data.col] == 0)//说明没有加入过buffer
- {
- buffer.push_back(pSearch);
- pathMap_isAddBuff[pSearch->data.row][pSearch->data.col] =1;//加完之后,修改
- }
-
- //双向设置!->parent和child
- pCurrent->pChild.push_back(pSearch);
- pSearch->pParent = pCurrent;
- //求出该节点的f和h
- pSearch->data.getH(endPos);
- pSearch->data.getF();
- }
- else{delete pSearch; pSearch = nullptr;}//不能走的地方就不放进去了
- }
-
- if (buffer.empty())break;//若添加完周边可能走的点之后size仍然为0,说明能走的点已经走完了
- //选择出f_cost最小的(在buffer中),pCurrent更新为最小点->删除在buffer中的位置(专门应对死胡同的情况)
- auto pmin = buffer.begin();
- for (auto p = buffer.begin(); p != buffer.end(); p++)
- {
- pmin = ((( * p)->data.f < (* pmin)->data.f) ? p : pmin);
- }//遍历出指向f_min位置的迭代器
- pCurrent = *pmin;//更新pCurrent
- pathMap[pCurrent->data.row][pCurrent->data.col] = 1;//选择的点标记走过
- buffer.erase(pmin);//删除在buffer中的位置
- //test
- Point a = { 3,0 };
- /*cout << "(" << pCurrent->data.row << "," << pCurrent->data.col << ")" << " ";
- if (pCurrent->data == a)
- while (1);*/
- if (pCurrent->data == endPos)isFind = true;
- //if (buffer.empty())break;//说明能走的点已经走完了----->7.30 不应该放在这里判断(应该在添加完之后,size仍然为0再去判断
- }
- if (isFind)
- {
- while (pCurrent)
- {
- cout << "找到啦!" << endl;
- cout << "(" << pCurrent->data.row << "," << pCurrent->data.col << ")" << " ";
- pCurrent = pCurrent->pParent;
- }
- }
- else
- {
- cout << "not found ,没找到捏" << endl;
- }
- return 0;
- }
-
- void Point::getH(const Point& end)
- {
- h = abs(row - end.row) * Direct_Cost + abs(col - end.col) * Direct_Cost;//曼哈顿距离->勿忘记乘上直线代价
- }
- bool CanWalk(const Point& p, bool pathmap[ROWS][COLS], bool MAP[ROWS][COLS])
- {
- bool flag = true;
- //1.越界不能走
- if (p.col < 0 || p.col >= COLS || p.row < 0 || p.row >= ROWS)flag = false;
- //2.放入到buffer里面的点,不能走
- if (pathmap[p.row][p.col]==1)flag = false;
- //3.是墙(1)不能走
- if (MAP[p.row][p.col]==1)flag = false;
- return flag;
- }
受此样例启发:
①需要额外增加一个辅助地图,用来标记每个点是否放入过buffer,否则buffer会重复放入多次一个相同的点
②不能在while的最后用buffer.size()==0来break,因为当
在A点时候,buffer只存在B,所以current移到B,此后删除B,则size==0直接break导致错误(实际上,B还是可以往C方向走的)
---->解决:在添加完周边可能的点到buffer之后,再去判断size!!!
最终运行:


去掉之后->

会有这样的报错->总结:在cpp中最好也是将struct 起一下别名or直接用class +public


可以采用优先队列当buffer(默认less,即队首是最大的),每次无序遍历,直接erase()即可。
Day14:C++之STL容器(2/3)__
https://blog.csdn.net/zjjaibc/article/details/125402421