• Day10:寻路算法值之A*寻路算法


    一、概要:

    ①以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的计算方法:

    两种计算方法->本处采用曼哈顿距离 

    二、代码实现

    1. #include //有abs
    2. #include
    3. using namespace std;
    4. #define ROWS 10
    5. #define COLS 10
    6. #define Direct_Cost 10
    7. #define Oblique_Cost 14
    8. bool CanWalk(const struct Point& p, bool pathmap[ROWS][COLS], bool MAP[ROWS][COLS]);
    9. //准备->①辅助地图 ②MAP ③树节点类型 ④坐标类型 ⑤buffer存储已经检测过的点 ⑥方向的枚举类型
    10. bool pathMap[ROWS][COLS] = { 0 };//0表示没有走过
    11. bool pathMap_isAddBuff[ROWS][COLS] = { 0 };
    12. bool MAP[ROWS][COLS] =
    13. {
    14. { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 },//0
    15. { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 },//1
    16. { 0, 0, 1, 1, 1, 0, 0, 0, 0, 0 },//2
    17. { 0, 1, 0, 1, 1, 0, 0, 0, 0, 0 },//3
    18. { 0, 1, 1, 0, 1, 0, 0, 1, 0, 0 },//4
    19. { 0, 0, 1, 1, 1, 0, 1, 1, 0, 0 },//5
    20. { 0, 0, 0, 0, 1, 0, 1, 0, 0, 0 },//6
    21. { 1, 0, 1, 1, 1, 0, 1, 0, 0, 0 },//7
    22. { 0, 1, 1, 0, 0, 1, 1, 0, 0, 0 },//8
    23. { 0, 0, 0, 1, 1, 0, 1, 0, 0, 0 }//9
    24. };
    25. struct Point
    26. {
    27. int row;
    28. int col;
    29. int f, g, h;
    30. bool operator==(const Point& a) { return (row == a.row && col == a.col); }
    31. void getH(const Point& end);
    32. void getF() { f = g + h; };
    33. };
    34. struct treeNode
    35. {
    36. Point data;
    37. treeNode *pParent;
    38. vectorpChild;
    39. treeNode() = default;
    40. treeNode(const Point& d)
    41. {
    42. treeNode* pNew = new treeNode;
    43. pParent = nullptr;
    44. data = d;
    45. }
    46. };
    47. vectorbuffer;
    48. enum dir{UP,RIGHT,DOWN,LEFT,RIGHT_UP,RIGHT_DOWN,LEFT_DOWN,LEFT_UP};
    49. int main()
    50. {
    51. Point begPos = { 0,0 }; //起点和终点
    52. Point endPos = { 6,7 };
    53. treeNode *pRoot=new treeNode(begPos);
    54. pathMap_isAddBuff[pRoot->data.row][pRoot->data.col] = 1;
    55. bool isFind = false;
    56. treeNode *pCurrent=pRoot;
    57. treeNode *pSearch;
    58. while (!isFind)
    59. {
    60. for (int i = 0; i < 8; i++)
    61. {
    62. pSearch = new treeNode(pCurrent->data);//每次进来都要重置pSearch->切不能修改到pCurrent的data!!!!
    63. switch (i)
    64. {
    65. case UP:pSearch->data.row--; pSearch->data.g += Direct_Cost; break;
    66. case DOWN:pSearch->data.row++; pSearch->data.g += Direct_Cost; break;
    67. case RIGHT:pSearch->data.col++; pSearch->data.g += Direct_Cost; break;
    68. case LEFT:pSearch->data.col--; pSearch->data.g += Direct_Cost; break;
    69. case RIGHT_DOWN:pSearch->data.row++; pSearch->data.col++; pSearch->data.g += Oblique_Cost; break;
    70. case RIGHT_UP:pSearch->data.row--; pSearch->data.col++; pSearch->data.g += Oblique_Cost; break;
    71. case LEFT_DOWN:pSearch->data.row++; pSearch->data.col--; pSearch->data.g += Oblique_Cost; break;
    72. case LEFT_UP:pSearch->data.row--; pSearch->data.col--; pSearch->data.g += Oblique_Cost; break;
    73. }
    74. if (CanWalk(pSearch->data, pathMap, MAP))
    75. {
    76. if (pathMap_isAddBuff[pSearch->data.row][pSearch->data.col] == 0)//说明没有加入过buffer
    77. {
    78. buffer.push_back(pSearch);
    79. pathMap_isAddBuff[pSearch->data.row][pSearch->data.col] =1;//加完之后,修改
    80. }
    81. //双向设置!->parent和child
    82. pCurrent->pChild.push_back(pSearch);
    83. pSearch->pParent = pCurrent;
    84. //求出该节点的f和h
    85. pSearch->data.getH(endPos);
    86. pSearch->data.getF();
    87. }
    88. else{delete pSearch; pSearch = nullptr;}//不能走的地方就不放进去了
    89. }
    90. if (buffer.empty())break;//若添加完周边可能走的点之后size仍然为0,说明能走的点已经走完了
    91. //选择出f_cost最小的(在buffer中),pCurrent更新为最小点->删除在buffer中的位置(专门应对死胡同的情况)
    92. auto pmin = buffer.begin();
    93. for (auto p = buffer.begin(); p != buffer.end(); p++)
    94. {
    95. pmin = ((( * p)->data.f < (* pmin)->data.f) ? p : pmin);
    96. }//遍历出指向f_min位置的迭代器
    97. pCurrent = *pmin;//更新pCurrent
    98. pathMap[pCurrent->data.row][pCurrent->data.col] = 1;//选择的点标记走过
    99. buffer.erase(pmin);//删除在buffer中的位置
    100. //test
    101. Point a = { 3,0 };
    102. /*cout << "(" << pCurrent->data.row << "," << pCurrent->data.col << ")" << " ";
    103. if (pCurrent->data == a)
    104. while (1);*/
    105. if (pCurrent->data == endPos)isFind = true;
    106. //if (buffer.empty())break;//说明能走的点已经走完了----->7.30 不应该放在这里判断(应该在添加完之后,size仍然为0再去判断
    107. }
    108. if (isFind)
    109. {
    110. while (pCurrent)
    111. {
    112. cout << "找到啦!" << endl;
    113. cout << "(" << pCurrent->data.row << "," << pCurrent->data.col << ")" << " ";
    114. pCurrent = pCurrent->pParent;
    115. }
    116. }
    117. else
    118. {
    119. cout << "not found ,没找到捏" << endl;
    120. }
    121. return 0;
    122. }
    123. void Point::getH(const Point& end)
    124. {
    125. h = abs(row - end.row) * Direct_Cost + abs(col - end.col) * Direct_Cost;//曼哈顿距离->勿忘记乘上直线代价
    126. }
    127. bool CanWalk(const Point& p, bool pathmap[ROWS][COLS], bool MAP[ROWS][COLS])
    128. {
    129. bool flag = true;
    130. //1.越界不能走
    131. if (p.col < 0 || p.col >= COLS || p.row < 0 || p.row >= ROWS)flag = false;
    132. //2.放入到buffer里面的点,不能走
    133. if (pathmap[p.row][p.col]==1)flag = false;
    134. //3.是墙(1)不能走
    135. if (MAP[p.row][p.col]==1)flag = false;
    136. return flag;
    137. }

     受此样例启发:

            ①需要额外增加一个辅助地图,用来标记每个点是否放入过buffer,否则buffer会重复放入多次一个相同的点

            ②不能在while的最后用buffer.size()==0来break,因为当

    在A点时候,buffer只存在B,所以current移到B,此后删除B,则size==0直接break导致错误(实际上,B还是可以往C方向走的)

    ---->解决:在添加完周边可能的点到buffer之后,再去判断size!!!

     最终运行:

    三、bug一览

            ①周围可以走的点加入buffer,在标记走过的时候,应该是加入buffer的点都应该标记->否则每走到下一个点的时候,buffer会增加重复已经增加过的点->导致死循环(别忘记标记)

            ②二维数组传参 bool* arr[ ]是与bool arr[ ][ ]不兼容的

            ③点运算符和->运算符的优先级是高于*运算符的!

             ④编译错误:

     去掉之后->

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

            ⑤memset并没有将pParent置为nullptr!!

     四、其他可能做出的改进

    可以采用优先队列当buffer(默认less,即队首是最大的),每次无序遍历,直接erase()即可。

    Day14:C++之STL容器(2/3)__https://blog.csdn.net/zjjaibc/article/details/125402421

  • 相关阅读:
    npm常用命令与操作篇
    LLaMA2模型训练加速秘籍:700亿参数效率提升195%!
    Qt+FFmpeg+opengl从零制作视频播放器-12.界面美化
    牛客刷题<32~34>非整数倍数和整数倍数数据位宽转换
    07-Redis【Redis主从复制,终于有人讲明白了】
    LAL v0.32.0发布,更好的支持纯视频流
    flume安装
    caxa复制尺寸错乱
    EditPlus 配置python 及Anaconda中的python
    Semantic-Guided Zero-Shot Learning for Low-Light ImageVideo Enhancement
  • 原文地址:https://blog.csdn.net/zjjaibc/article/details/126067337