图遍历算法——DFS、BFS、A*、B*和Flood Fill 遍历算法串串烧

本文内容框架:

§1 图遍历DFS和BFS两种实现

§2 A*算法

§3 B*算法

§4 Flood Fill算法

§5 小结

图遍历问题分为四类:

遍历完所有的边而不能有重复,即所謂“一笔画问题”或“欧拉路径”;

遍历完所有的顶点而没有重复,即所谓“哈密尔顿问题”。

遍历完所有的边而可以有重复,即所谓“中国邮递员问题”;

遍历完所有的顶点而可以重复,即所谓“旅行推销员问题”。

 

对于第一和第三类问题已经得到了完满的解决,而第二和第四类问题则只得到了部分解决。

第一类问题就是研究所谓的欧拉图的性质,而第二类问题则是研究所谓的哈密尔顿图的性质。

 

 

 

§1 图遍历DFS和BFS两种实现

 

图遍历的矩阵存储和邻接表存储的BFS和DFS实现

矩阵存储BFS

 

C代码 复制代码  收藏代码
  1. #include <stdio.h>   
  2. #include <string.h>   
  3. #include <queue>   
  4. using namespace std;   
  5. queue <int> qu, qq;   
  6. int map[100][100], m, n, judge[100], path[100];   
  7. void bfs(){//和导论上的染色的方法差不多,judge[0] == 0 时候代表白色节点   在队列里面的节点是灰色的 出队列的是黑色的。   
  8.     int w, s,t,i, j;   
  9.     while(true){   
  10.         s = qu.size();   
  11.         if(!s)return;   
  12.         while(s--){   
  13.             t = qu.front();   
  14.             for(i = 0; i < n; i++){   
  15.                 if(map[t][i] && !judge[i]){   
  16.                     judge[i] = true;   
  17.                     qu.push(i);   
  18.                     path[i] = t;//记录宽度优先搜索树中的当前节点的父亲   
  19.                     //printf("path[%d] = %d\n", i, t);   
  20.                 }   
  21.             }   
  22.             qu.pop();   
  23.         }   
  24.     }   
  25. }   
  26. void printpath(int n){ //递归的输出路径   
  27.     if(path[n] == -1)printf("%d ", n);   
  28.     else{   
  29.         printpath(path[n]);   
  30.         printf("%d ", n);   
  31.     }   
  32. }   
  33. int main(){   
  34.     freopen("bfs.in""r", stdin);   
  35.     freopen("bfs.out""w", stdout);   
  36.     int i, j, u, v;   
  37.     while(scanf("%d%d", &n, &m) != -1){   
  38.         memset(judge, 0, sizeof(judge));   
  39.         for(i = 0; i < m; i++){   
  40.             scanf("%d%d", &u, &v);   
  41.             map[u][v] = map[v][u] = 1;   
  42.         }   
  43.         judge[0] = true;qu = qq;   
  44.         qu.push(0);memset(path, -1, sizeof(path));   
  45.         bfs();   
  46.         for(i = 1; i < n; i++){   
  47.             printf("from 0 to %d : ", i);   
  48.             printpath(i);puts("");   
  49.         }   
  50.     }   
  51.     return 0;   
  52. }  
 

链表存储BFS

 

C代码 复制代码  收藏代码
  1. #include <stdio.h>   
  2. #include <string.h>   
  3. #include <queue>   
  4. using namespace std;   
  5. queue<int> qu, qq;   
  6. struct e{   
  7.     int v;   
  8.     e* next;   
  9. };   
  10. e* edge[100];int m, n, judge[100], path[100];   
  11. void bfs(){   
  12.     int w, i, j, t, s;e* l;   
  13.     while(true){   
  14.         s = qu.size();   
  15.         if(!s)return;   
  16.         while(s--){   
  17.             w = qu.front();   
  18.             l = edge[w];   
  19.             while(l){   
  20.                 t = l->v;   
  21.                 if(!judge[t]){   
  22.                     judge[t] = true;   
  23.                     qu.push(t);   
  24.                     path[t] = w;   
  25.                 }   
  26.                 l = l->next;   
  27.             }   
  28.             qu.pop();   
  29.         }   
  30.     }   
  31. }   
  32. void printpath(int x){   
  33.     if(path[x] == -1)printf("%d ", x);   
  34.     else{   
  35.         printpath(path[x]);   
  36.         printf(" %d", x);   
  37.     }   
  38. }   
  39. int main(){  //个人不推荐动态开辟存储空间,建议静态。   
  40.     freopen("bfs_link.in""r", stdin);   
  41.     freopen("bfs_link.out""w", stdout);   
  42.     int u, v, i, j;e* node;   
  43.     while(scanf("%d%d", &n, &m) != -1){   
  44.         memset(judge, 0, sizeof(judge));   
  45.         memset(path, -1, sizeof(path));   
  46.         for(i = 0; i < m; i++){   
  47.             scanf("%d%d", &u, &v);   
  48.             node = new e;   
  49.             node->v = v;   
  50.             node->next = edge[u];   
  51.             edge[u] = node;   
  52.             node = new e;   
  53.             node->v = u;   
  54.             node->next = edge[v];   
  55.             edge[v] = node;   
  56.         }   
  57.         judge[0] = true;qu = qq;qu.push(0);   
  58.         bfs();   
  59.         for(i = 1; i < n; i++){   
  60.             printf("path from 0 to %d : ", i);   
  61.             printpath(i);puts("");   
  62.         }   
  63.     }   
  64.     return 0;   
  65. }  
 

矩阵存储DFS

 

C代码 复制代码  收藏代码
  1. #include <stdio.h>   
  2. #include <string.h>   
  3. int map[100][100], m, n, d[100], f[100], time, path[100];   
  4. bool judge[100];   
  5. void dfs(int v){   
  6.     int i;judge[v] = true;   
  7.     time++;d[v] = time;//开始时间   
  8.     for(i = 0; i < n; i++){   
  9.         if(map[v][i] && !judge[i]){   
  10.             path[i] = v;//记录深度优先搜索树中的父亲节点   
  11.             dfs(i);   
  12.         }   
  13.     }   
  14.     time++;f[v] = time;//结束时间   
  15. }   
  16.   
  17. void printpath(int v){   
  18.     if(path[v] == -1)printf("%d ", v);   
  19.     else{   
  20.         printpath(path[v]);   
  21.         printf(" %d", v);   
  22.     }   
  23. }   
  24.   
  25. int main(){   
  26.     freopen("dfs_m.in""r", stdin);   
  27.     freopen("dfs_m.out""w", stdout);   
  28.     int i, j, u, v;   
  29.     while(scanf("%d%d", &n, &m) != -1){   
  30.         memset(map, 0, sizeof(map));   
  31.         memset(judge, 0, sizeof(judge));   
  32.         memset(path, -1, sizeof(path));   
  33.         for(i = 0; i < m; i++){   
  34.             scanf("%d%d", &u, &v);   
  35.             map[u][v] = map[v][u] = true;   
  36.         }   
  37.         time = 0;dfs(0);   
  38.         for(i = 0; i < n; i++){   
  39.             printf("d[%d] = %d   f[%d] = %d\n", i, d[i], i, f[i]);   
  40.         }   
  41.         for(i = 1; i < n; i++){   
  42.             printf("path from 0 to %d : ");   
  43.             printpath(i);puts("");   
  44.         }   
  45.     }   
  46.     return 0;   
  47. }  
 

链表存储BFS

 

C代码 复制代码  收藏代码
  1. #include <stdio.h>   
  2. #include <string.h>   
  3. struct e{   
  4.     int v;   
  5.     e* next;   
  6. };   
  7. e* link[100];e edge[10000];//静态的   
  8. int m, n, el, judge[100], d[100], f[100], time, path[100];   
  9. void dfs(int v){   
  10.     int i, t;e* l;   
  11.     judge[v] = true;   
  12.     time++;d[v] = time;   
  13.     l = link[v];   
  14.     while(l){   
  15.         t = l->v;   
  16.         if(!judge[t]){   
  17.             judge[t] = true;   
  18.             path[t] = v;   
  19.             dfs(t);   
  20.         }   
  21.         l = l->next;   
  22.     }   
  23.     time++;f[v] = time;   
  24. }   
  25.   
  26. void printpath(int v){   
  27.     if(path[v] == -1)printf("%d", v);   
  28.     else{   
  29.         printpath(path[v]);   
  30.         printf(" %d", v);   
  31.     }   
  32. }   
  33.   
  34. int main(){   
  35.     freopen("dfs_link.in""r", stdin);   
  36.     freopen("dfs_link.out""w", stdout);   
  37.     int i, j, u, v;   
  38.     while(scanf("%d%d", &n, &m) != -1){   
  39.         memset(judge, 0, sizeof(judge));   
  40.         memset(link, 0, sizeof(edge));   
  41.         memset(path, -1, sizeof(path));   
  42.         for(i = 0, el = 0; i < m; i++){   
  43.             scanf("%d%d", &u, &v);   
  44.             edge[el].v = v;   
  45.             edge[el].next = link[u];   
  46.             link[u] = &edge[el++];   
  47.             edge[el].v = u;   
  48.             edge[el].next = link[v];   
  49.             link[v] = &edge[el++];   
  50.         }time = 0;   
  51.         for(i = 0; i < n; i++){   
  52.             if(!judge[i])dfs(i);   
  53.         }   
  54.         for(i = 0; i < n; i++){   
  55.             printf("d[%d] = %d  f[%d] = %d\n", i, d[i], i, f[i]);   
  56.         }   
  57.         for(i = 1; i < n; i++){   
  58.             printf("path form 0 to %d : ", i);   
  59.             printpath(i);puts("");   
  60.         }   
  61.     }   
  62.     return 0;   
  63. }  

  ╝①

 

§2 A*算法

 

A*算法

 

A*算法是一种常用的启发式搜索算法。


在A*算法中,一个结点位置的好坏用估价函数来对它进行评估。A*算法的估价函数可表示为: 
f'(n) = g'(n) + h'(n) 
这里,f'(n)是估价函数,g'(n)是起点到终点的最短路径值(也称为最小耗费或最小代价),h'(n)是n到目标的最短路经的启发值。由于这个f'(n)其实是无法预先知道的,所以实际上使用的是下面的估价函数:
f(n) = g(n) + h(n) 
其中g(n)是从初始结点到节点n的实际代价,h(n)是从结点n到目标结点的最佳路径的估计代价。在这里主要是h(n)体现了搜索的启发信息,因为g(n)是已知的。用f(n)作为f'(n)的近似,也就是用g(n)代替g'(n),h(n)代替h'(n)。这样必须满足两个条件:(1)g(n)>=g'(n)(大多数情况下都是满足的,可以不用考虑),且f必须保持单调递增。(2)h必须小于等于实际的从当前节点到达目标节点的最小耗费h(n)<=h'(n)。第二点特别的重要。可以证明应用这样的估价函数是可以找到最短路径的。


A*算法的具体步骤
A*算法基本上与广度优先算法相同,但是在扩展出一个结点后,要计算它的估价函数,并根据估价函数对待扩展的结点排序,从而保证每次扩展的结点都是估价函数最小的结点。
1)建立一个队列,计算初始结点的估价函数f,并将初始结点入队,设置队列头和尾指针。
2)取出队列头(队列头指针所指)的结点,如果该结点是目标结点,则输出路径,程序结束。否则对结点进行扩展。 
3)检查扩展出的新结点是否与队列中的结点重复,若与不能再扩展的结点重复(位于队列头指针之前),则将它抛弃;若新结点与待扩展的结点重复(位于队列头指针之后),则比较两个结点的估价函数中g的大小,保留较小g值的结点。跳至第五步。
4)如果扩展出的新结点与队列中的结点不重复,则按照它的估价函数f大小将它插入队列中的头结点后待扩展结点的适当位置,使它们按从小到大的顺序排列,最后更新队列尾指针。
5)如果队列头的结点还可以扩展,直接返回第二步。否则将队列头指针指向下一结点,再返回第二步。

╝②

 

A*算法图解

 

 如图所示简易地图, 其中绿色方块的是起点 (用 A 表示), 中间蓝色的是障碍物, 红色的方块 (用 B 表示) 是目的地. 为了可以用一个二维数组来表示地图, 我们将地图划分成一个个的小方块。

 

 

 

二维数组在游戏中的应用是很多的, 比如贪吃蛇和俄罗斯方块基本原理就是移动方块而已. 而大型游戏的地图, 则是将各种"地貌"铺在这样的小方块上。

 

 


F = G + H,               

G 表示从起点 A 移动到网格上指定方格的移动耗费 (可沿斜方向移动)。 

H 表示从指定的方格移动到终点 B 的预计耗费 (H 有很多计算方法, 这里我们设定只可以上下左右移动)。

   我们假设横向移动一个格子的耗费为10, 为了便于计算, 沿斜方向移动一个格子耗费是14. 为了更直观的展示如何运算 F,G,H, 图中方块的左上角数字表示 F, 左下角表示 G, 右下角表示 H。 看看上图是否跟你心里想的结果一样?

 将上图A周围的方块全部放入队列,取出F值最小的方块C,看看 C 下面的那个格子, 它目前的 G 是14, 如果通过 C 到达它的话, G将会是 10 + 10, 这比 14 要大, 因此我们什么也不做(上面步骤3))。

以C为中心结点,扩展新结点 ,并进入队列(上面步骤4))。

直到最终找到终点B,上面浅蓝色边缘的方块是移动过的地点(实际走过的地方),浅绿色边缘的方块是还在队列中的方块。

╝③  

A*算法实现

 

C代码 复制代码  收藏代码
  1. /*  
  2.  * file: astar_algorithm.h  
  3.  * author: MulinB@HUST  
  4.  * date: 2010-10-10  
  5.  * modified: 2012-05-09  
  6.  * A-star algorithm implemented in C. Only for study.  
  7.  */  
  8. #ifndef _ASTAR_ALGORITHM_H   
  9. #define _ASTAR_ALGORITHM_H   
  10. #include <math.h>   
  11. #define M  6   
  12. #define N  8   
  13. //map marks   
  14. #define  AVAIL     0   
  15. #define  UNAVAIL  -1   
  16. #define  START   100   
  17. #define  END     111   
  18. #define  ROAD     10   
  19. #define GET_F(X)  (X->G + X->H)   
  20. typedef struct Node   
  21. {   
  22.     //for node itself   
  23.     int type; //node type   
  24.     int i; //i index   
  25.     int j; //j index   
  26.     //for A star algorithm   
  27.     double G; //past road cost   
  28.     double H; //heuristic, F = G + H   
  29.     struct Node* parent; //parent node, used for trace road   
  30.     struct Node* next; //only used for open and close list   
  31. }Node;   
  32.   
  33. //==========================open close list operation================   
  34. Node* open_list;   
  35. Node* close_list;   
  36. void init_openlist()   
  37. {   
  38.     open_list = NULL;   
  39. }   
  40. void init_closelist()   
  41. {   
  42.     close_list = NULL;   
  43. }   
  44. void destroy_openlist()   
  45. {   
  46.     Node* q;   
  47.     Node* p = open_list;   
  48.     while (p != NULL)   
  49.     {   
  50.         q = p->next;   
  51.         free(p);   
  52.         p = q;   
  53.     }   
  54. }   
  55. void destroy_closelist()   
  56. {   
  57.     Node* q;   
  58.     Node* p = close_list;   
  59.     while (p != NULL)   
  60.     {   
  61.         q = p->next;   
  62.         free(p);   
  63.         p = q;   
  64.     }   
  65. }   
  66. void insert_into_openlist(Node* new_node) //insert and sort by F   
  67. {   
  68.     Node* p;   
  69.     Node* q;   
  70.     if (open_list == NULL)   
  71.     {   
  72.         open_list = new_node; //insert as the first   
  73.         return;   
  74.     }   
  75.     p = open_list;   
  76.     while (p != NULL)   
  77.     {   
  78.         q = p;   
  79.         p = p->next;   
  80.         if (p == NULL)   
  81.         {   
  82.             q->next = new_node; //insert as the last   
  83.             return;   
  84.         }   
  85.         else if (GET_F(new_node) < GET_F(p))   
  86.         {   
  87.             q->next = new_node; //insert before p, sorted   
  88.             new_node->next = p;   
  89.             return;   
  90.         }   
  91.     }   
  92.        
  93. }   
  94. void insert_into_closelist(Node* new_node) //just insert before head   
  95. {   
  96.     if (close_list == NULL)   
  97.     {   
  98.         close_list = new_node; //insert as the first   
  99.         return;   
  100.     }   
  101.     else  
  102.     {   
  103.         new_node->next = close_list; //insert before head   
  104.         close_list = new_node;   
  105.         return;   
  106.     }   
  107. }   
  108. Node* find_node_in_list_by_ij(Node* node_list, int di, int dj)   
  109. {   
  110.     Node* p = node_list;   
  111.     while (p)   
  112.     {   
  113.         if (p->i == di && p->j == dj)   
  114.             return p;   
  115.         p = p->next;   
  116.     }   
  117.     return NULL;   
  118. }   
  119. Node* pop_firstnode_from_openlist() //get the minimum node sorted by F   
  120. {   
  121.     Node* p = open_list;   
  122.     if (p == NULL)   
  123.     {   
  124.         return NULL;   
  125.     }   
  126.     else  
  127.     {   
  128.         open_list = p->next;   
  129.         p->next = NULL;   
  130.         return p;   
  131.     }   
  132. }   
  133. void remove_node_from_openlist(Node* nd) //just remove it, do not destroy it   
  134. {   
  135.     Node* q;   
  136.     Node* p = open_list;   
  137.     if (open_list == nd)   
  138.     {   
  139.         open_list = open_list->next;   
  140.         return;   
  141.     }   
  142.     while (p)   
  143.     {   
  144.         q = p;   
  145.         p = p->next;   
  146.         if (p == nd) //found   
  147.         {   
  148.             q->next = p->next;   
  149.             p->next = NULL;   
  150.             return;   
  151.         }   
  152.     }   
  153. }   
  154. void remove_node_from_closelist(Node* nd) //just remove it, do not destroy it   
  155. {   
  156.     Node* q;   
  157.     Node* p = close_list;   
  158.     if (close_list == nd)   
  159.     {   
  160.         close_list = close_list->next;   
  161.         return;   
  162.     }   
  163.     while (p)   
  164.     {   
  165.         q = p;   
  166.         p = p->next;   
  167.         if (p == nd) //found   
  168.         {   
  169.             q->next = p->next;   
  170.             p->next = NULL;   
  171.             return;   
  172.         }   
  173.     }   
  174. }   
  175. //===================================================================   
  176. //=======================calculate H, G =============================   
  177. //calculate Heuristic value   
  178. //(reimplemented when porting a star to another application)   
  179. double calc_H(int cur_i, int cur_j, int end_i, int end_j)   
  180. {   
  181.     return (abs(end_j - cur_j) + abs(end_i - cur_i)) * 10.0; //the heuristic   
  182. }   
  183. //calculate G value   
  184. //(reimplemented when porting a star to another application)   
  185. double calc_G(Node* cur_node)   
  186. {   
  187.     Node* p = cur_node->parent;   
  188.     if (abs(p->i - cur_node->i) + abs(p->j - cur_node->j) > 1)   
  189.         return 14.0 + p->G; //the diagonal cost is 14   
  190.     else  
  191.         return 10.0 + p->G; //the adjacent cost is 10   
  192. }   
  193. void init_start_node(Node* st, int si, int sj, int ei, int ej)   
  194. {   
  195.     memset(st, 0, sizeof(Node));   
  196.     st->type = START;   
  197.     st->i = si;   
  198.     st->j = sj;   
  199.     st->H = calc_H(si, sj, ei, ej);   
  200.     st->G = 0;   
  201. }   
  202. void init_end_node(Node* ed, int ei, int ej)   
  203. {   
  204.     memset(ed, 0, sizeof(Node));   
  205.     ed->type = END;   
  206.     ed->i = ei;   
  207.     ed->j = ej;   
  208.     ed->H = 0;   
  209.     ed->G = 9999; //temp value   
  210. }   
  211. void init_pass_node(Node* pd, int pi, int pj)   
  212. {   
  213.     memset(pd, 0, sizeof(Node));   
  214.     pd->type = AVAIL;   
  215.     pd->i = pi;   
  216.     pd->j = pj;   
  217. }   
  218. //check the candidate node (i,j) when extending parent_node   
  219. int check_neighbor(int map[][N], int width, int height,    
  220.     int di, int dj, Node* parent_node, Node* end_node)   
  221. {   
  222.     Node* p;   
  223.     Node* temp;   
  224.     double new_G;   
  225.     if (di < 0 || dj < 0 || di > height-1 || dj > width-1)   
  226.         return UNAVAIL;   
  227.     //1. check available   
  228.     if (map[di][dj] == UNAVAIL)   
  229.         return UNAVAIL;   
  230.     //2. check if existed in close list   
  231.     p = find_node_in_list_by_ij(close_list, di, dj);    
  232.     if (p != NULL)   
  233.     {   
  234.         //found in the closed list, check if the new G is better, added 2012-05-09   
  235.         temp = p->parent;   
  236.         p->parent = parent_node;   
  237.         new_G = calc_G(p);   
  238.         if (new_G >= p->G)   
  239.         {   
  240.             p->parent = temp; //if new_G is worse, recover the parent   
  241.         }   
  242.         else  
  243.         {   
  244.             //the new_G is better, remove it from close list, insert it into open list   
  245.             p->G = new_G;   
  246.             remove_node_from_closelist(p); //remove it   
  247.             insert_into_openlist(p); //insert it, sorted   
  248.         }   
  249.         return AVAIL;   
  250.     }   
  251.     //3. check if existed in open list   
  252.     p = find_node_in_list_by_ij(open_list, di, dj); //in open list   
  253.     if (p != NULL)   
  254.     {   
  255.         //found in the open list, check if the new G is better   
  256.         temp = p->parent;   
  257.         p->parent = parent_node;   
  258.         new_G = calc_G(p);   
  259.         if (new_G >= p->G)   
  260.         {   
  261.             p->parent = temp; //if new_G is worse, recover the parent   
  262.         }   
  263.         else  
  264.         {   
  265.             //the new_G is better, resort the list   
  266.             p->G = new_G;   
  267.             remove_node_from_openlist(p); //remove it   
  268.             insert_into_openlist(p); //insert it, sorted   
  269.         }   
  270.         return AVAIL;   
  271.     }   
  272.        
  273.     //4. none of above, insert a new node into open list   
  274.     if (map[di][dj] == END)   
  275.     {   
  276.         //4~. check if it is end node   
  277.         end_node->parent = parent_node;   
  278.         end_node->G = calc_G(end_node);   
  279.         insert_into_openlist(end_node); //insert into openlist   
  280.         return AVAIL;   
  281.     }   
  282.     else  
  283.     {   
  284.         //4~~. create a new node   
  285.         p = malloc(sizeof(Node));   
  286.         init_pass_node(p, di, dj);   
  287.         p->parent = parent_node;   
  288.         p->H = calc_H(di, dj, end_node->i, end_node->j);   
  289.         p->G = calc_G(p);   
  290.         insert_into_openlist(p); //insert into openlist   
  291.         return AVAIL;   
  292.     }   
  293. }   
  294. //extend the current node on the map   
  295. //(reimplemented when porting a star to another application)   
  296. void extend_node(Node* cd, int map[][N], int width, int height, Node* end_node)   
  297. {   
  298.     int up_status, down_status, left_status, right_status;   
  299.     int ci, cj; //cur node i, j   
  300.     int ti, tj; //temp i, j   
  301.     ci = cd->i;   
  302.     cj = cd->j;   
  303.     //1. up   
  304.     ti = ci - 1;   
  305.     tj = cj;   
  306.     up_status = check_neighbor(map, width, height, ti, tj, cd, end_node);   
  307.     //2. down   
  308.     ti = ci + 1;   
  309.     tj = cj;   
  310.     down_status = check_neighbor(map, width, height, ti, tj, cd, end_node);   
  311.     //3. left   
  312.     ti = ci;   
  313.     tj = cj - 1;   
  314.     left_status = check_neighbor(map, width, height, ti, tj, cd, end_node);   
  315.     //4. right   
  316.     ti = ci;   
  317.     tj = cj + 1;   
  318.     right_status = check_neighbor(map, width, height, ti, tj, cd, end_node);   
  319.     //5. leftup   
  320.     ti = ci - 1;   
  321.     tj = cj - 1;   
  322.     if (up_status == AVAIL && left_status == AVAIL)   
  323.         check_neighbor(map, width, height, ti, tj, cd, end_node);   
  324.     //6. rightup   
  325.     ti = ci - 1;   
  326.     tj = cj + 1;   
  327.     if (up_status == AVAIL && right_status == AVAIL)   
  328.         check_neighbor(map, width, height, ti, tj, cd, end_node);   
  329.     //7. leftdown   
  330.     ti = ci + 1;   
  331.     tj = cj - 1;   
  332.     if (down_status == AVAIL && left_status == AVAIL)   
  333.         check_neighbor(map, width, height, ti, tj, cd, end_node);   
  334.     //8. rightdown   
  335.     ti = ci + 1;   
  336.     tj = cj + 1;   
  337.     if (down_status == AVAIL && right_status == AVAIL)   
  338.         check_neighbor(map, width, height, ti, tj, cd, end_node);   
  339.        
  340. }   
  341.   
  342. //=======================search algorithm======================================   
  343. /*  
  344. A*方法总结 (from http://www.policyalmanac.org/games/aStarTutorial.htm):  
  345. 1. 把起始格添加到开启列表。  
  346. 2. 重复如下的工作:  
  347.   a) 寻找开启列表中F值最低的格子。我们称它为当前格。  
  348.   b) 把它切换到关闭列表。  
  349.   c) 对相邻的8格中的每一个?  
  350.     * 如果它不可通过或者已经在关闭列表中,略过它。反之如下。(MulinB 2012-05-09 按:在关闭列表中是否也应该检查它,看是否可以获得更低的G值?? ref: http://theory.stanford.edu/~amitp/GameProgramming/ImplementationNotes.html )  
  351.     * 如果它不在开启列表中,把它添加进去。把当前格作为这一格的父节点。记录这一格的F,G,和H值。  
  352.     * 如果它已经在开启列表中,用G值为参考检查新的路径是否更好。更低的G值意味着更好的路径。  
  353.       如果是这样,就把这一格的父节点改成当前格,并且重新计算这一格的G和F值。  
  354.       如果你保持你的开启列表按F值排序,改变之后你可能需要重新对开启列表排序。  
  355.   d) 停止,当你  
  356.     * 把目标格添加进了关闭列表(注解),这时候路径被找到,或者  
  357.     * 没有找到目标格,开启列表已经空了。这时候,路径不存在。  
  358. 3. 保存路径。从目标格开始,沿着每一格的父节点移动直到回到起始格。这就是你的路径。  
  359. */  
  360. //search a road on a map, return node_list   
  361. Node* a_star_search(int map[M][N], int width, int height,    
  362.                     int start_i, int start_j, int end_i, int end_j)   
  363. {   
  364.     Node* cur_node;   
  365.     Node* start_node;   
  366.     Node* end_node;   
  367.     //create start and end node   
  368.     start_node = malloc(sizeof(Node));   
  369.     init_start_node(start_node, start_i, start_j, end_i, end_j);   
  370.     end_node = malloc(sizeof(Node));   
  371.     init_end_node(end_node, end_i, end_j);   
  372.        
  373.     //init open and close list   
  374.     init_openlist();   
  375.     init_closelist();   
  376.     //put start_node into open list   
  377.     insert_into_openlist(start_node);   
  378.        
  379.     //start searching   
  380.     while (1)   
  381.     {   
  382.         cur_node = pop_firstnode_from_openlist(); //it has the minimum F value   
  383.         if (cur_node == NULL || cur_node->type == END)   
  384.         {   
  385.             break//found the road or no road found   
  386.         }   
  387.            
  388.         extend_node(cur_node, map, width, height, end_node); //the key step!!   
  389.         insert_into_closelist(cur_node);   
  390.     }   
  391.     //you can track the road by the node->parent   
  392.     return cur_node;   
  393. }   
  394.   
  395. #endif /* file end */  

 ╝④

 

 

B*算法

B* 寻路算法又叫Branch Star 分支寻路算法,且与A*对应,本算法适用于游戏中怪物的自动寻路,其效率远远超过A*算法,经过测试,效率是普通A*算法的几十上百倍。 
通过引入该算法,一定程度上解决了游戏服务器端无法进行常规寻路的效率问题,除非服务器端有独立的AI处理线程,否则在服务器端无法允许可能消耗大量时间的寻路搜索,即使是业界普遍公认的最佳的A*,所以普遍的折中做法是服务器端只做近距离的寻路,或通过导航站点缩短A*的范围。 

 

 

§3 B*算法

B*算法原理 
本算法启发于自然界中真实动物的寻路过程,并加以改善以解决各种阻挡问题(有点类似蚁群算法)。 
前置定义: 
1、探索节点: 
为了叙述方便,我们定义在寻路过程中向前探索的节点(地图格子)称为探索节点,起始探索节点即为原点。(探索节点可以对应为A*中的开放节点)。
2、自由的探索节点: 
探索节点朝着目标前进,如果前方不是阻挡,探索节点可以继续向前进入下一个地图格子,这种探索节点我们称为自由探索节点; 
3、绕爬的探索节点: 
探索节点朝着目标前进,如果前方是阻挡,探索节点将试图绕过阻挡,绕行中的探索节点我们成为绕爬的探索节点; 
B*算法流程 
1、起始,探索节点为自由节点,从原点出发,向目标前进; 
2、自由节点前进过程中判断前面是否为障碍, 
      a、不是障碍,向目标前进一步,仍为自由节点; 
      b、是障碍,以前方障碍为界,分出左右两个分支,分别试图绕过障碍,这两个分支节点即成为两个绕爬的探索节点; 
3、绕爬的探索节点绕过障碍后,又成为自由节点,回到2); 
4、探索节点前进后,判断当前地图格子是否为目标格子,如果是则寻路成功,根据寻路过程构造完整路径; 
5、寻路过程中,如果探索节点没有了,则寻路结束,表明没有目标格子不可达; 

B*算法图解演示 
     
    


B*算法与A*算法的性能比较 
寻路次数比较(5秒钟寻路次数) 

 

╝⑤

 

§4 Flood Fill算法

 

Flood Fill算法

 

Flood Fill算法是计算机图形学和数字图像处理的一个填充算法,其实就是从一点开始向四面周围寻找点填充遍历,原理和BFS很相似,当然也可以像DFS一样的遍历。

 

Flood Fill 算法图解演示


Flood Fill算法实现

说的Flood Fill算法的实现不得不提Lode's Computer Graphics Tutorial。该算法可以通过递归或者是stack来完成,下面只附上4-Way Recurisive Method:

 

Cpp代码 复制代码  收藏代码
  1. //Recursive 4-way floodfill, crashes if recursion stack is full    
  2. void floodFill4(int x, int y, int newColor, int oldColor)    
  3. {    
  4.     if(x >= 0 && x < w && y >= 0 && y < h && screenBuffer[x][y] == oldColor && screenBuffer[x][y] != newColor)    
  5.     {    
  6.         screenBuffer[x][y] = newColor; //set color before starting recursion   
  7.            
  8.         floodFill4(x + 1, y,     newColor, oldColor);   
  9.         floodFill4(x - 1, y,     newColor, oldColor);   
  10.         floodFill4(x,     y + 1, newColor, oldColor);   
  11.         floodFill4(x,     y - 1, newColor, oldColor);   
  12.     }        
  13. }  
//Recursive 4-way floodfill, crashes if recursion stack is full 
void floodFill4(int x, int y, int newColor, int oldColor) 
{ 
    if(x >= 0 && x < w && y >= 0 && y < h && screenBuffer[x][y] == oldColor && screenBuffer[x][y] != newColor) 
    { 
        screenBuffer[x][y] = newColor; //set color before starting recursion
        
        floodFill4(x + 1, y,     newColor, oldColor);
        floodFill4(x - 1, y,     newColor, oldColor);
        floodFill4(x,     y + 1, newColor, oldColor);
        floodFill4(x,     y - 1, newColor, oldColor);
    }     
}
 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值