吴昊品游戏核心算法 Round 13 —— 吴昊教你走迷宫(BFS)

 

 

  如图所示,这是一个手机游戏,走迷宫游戏发展到现在,已经存在不少变式了,比如现在利用android/ios系统的重力感应器功能做成的——《迷宫小 球》就是现在比较成功的一款(关于《迷宫小球》这款经典游戏,我会在《吴昊品工程级别项目源代码》中详细阐述)。我们这里只是抽出游戏的核心算法作为探 讨,其实,这也是我的一个想法,因为UI,美工以及架构等等,在设计的时候不会太难(当然,这里纠正一个误区,就是顶尖的设计师的难度高于顶尖的算法工程 师,但是一般的设计不会追求那种纯粹艺术级别吧!我想)。

 BFS的奥义:

  BFS是一种盲目搜寻法,目的是系统地展开并检查中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位址,彻底地搜索整张图,直到找到结果为止。BFS并不使用经验法则算法

 从算法的观点,所有因为展开节点而得到的子节点都会被加进一个先进先出伫列中。一般的实作里,其邻居节点尚未被检验过的节点会被放置在一个被称为 open 的容器中(例如伫列或是链表),而被检验过的节点则被放置在被称为 closed 的容器中。(open-closed表)

 

 我们的迷宫问题(Source:HDOJ 1728):

  Input:整个迷宫地图,可走的位置标为.而不可走的位置标为*(相当于一堵墙)。那么,我们给出最多需要转弯的数目和两个坐标(x1,y1)和(x2,y2)(这里是一个人为限制,所以,我们要用BFS选出一个最佳的策略)。

  Output:我们需要判断出这个人能否从一个位置走向另外一个位置,也就是输出yes或者是no就可以了,而具体怎么走很简单。

  Solve:

 

  1     /*
  2     Highlights:
  3               (1)定义了一个vis[101][101]来计数拐弯数目,并及时将其更改
  4               (2)将初始的方向定义为-1,因为初始的时候不存在拐弯不拐弯的问题,可以向任意方向拓展
  5               (3)利用STL里面的队列容器来存放结点
  6    */
  7 
  8    #include<iostream>
  9   // 这里开一个队列STL
 10   #include<queue>
 11   using  namespace std;
 12  
 13   // 这里开一个二维字符数组来装载地图
 14    char map[ 101][ 101];
 15  
 16   // n和m为实际地图的长与宽,ei和ej为地图的终点
 17    int n,m,T,ei,ej;
 18   // 方向数组,你懂的
 19    int dir[ 4][ 2]={{ 1, 0},{- 1, 0},{ 0, 1},{ 0,- 1}};
 20   // 特别地,这里标注一个二维数组vis[101][101]来标记每个位置已经拐弯了多少次
 21    int vis[ 101][ 101];
 22  
 23   // 每个结点有一个位置坐标,一个di标注当前的方向,turn标注拐了多少次弯
 24    struct node
 25  {
 26     int x,y,di,turn;
 27  };
 28  
 29   // 定义一个结点
 30   node f;
 31  
 32   void bfs()
 33  {
 34     // 队列结点Q
 35     queue<node> Q;
 36     // 将最开始(first)的那个结点放入队列
 37     Q.push(f);
 38     // 作为初始,我们还没有拐任何一次弯
 39     vis[f.x][f.y]= 0;
 40     while(!Q.empty())
 41    {
 42      node t=Q.front(),temp;
 43       // 出队列
 44       Q.pop();
 45       for( int k= 0;k< 4;k++)
 46      {
 47         // 从这四个方向中,每次尝试一个不同的方向
 48          int i=dir[k][ 0]+t.x;
 49         int j=dir[k][ 1]+t.y;
 50         // 出界或者遇到了障碍物,则continue
 51          if(i>n||i< 1||j>m||j< 1||map[i][j]== ' * 'continue;
 52         // 如果原来的那个结点对应的方向不是初始方向,而且和原来的方向不一样的话
 53          if(t.di!=k&&t.di!=- 1)
 54              temp.turn=t.turn+ 1;
 55         else temp.turn=t.turn; // 方向相同或刚出发
 56          // 如果超过了次数,则换一种方向
 57          if(temp.turn>T)  continue;
 58         // 找到最优解,则输出
 59          if(i==ei&&j==ej)
 60        {
 61          cout<< " yes "<<endl;
 62           return;
 63        }
 64         // 及时修正原来的结点,将拐弯数目控制在最小
 65          if(vis[i][j]>=temp.turn)
 66        {
 67          vis[i][j]=temp.turn;
 68          temp.x=i;
 69          temp.y=j;
 70          temp.di=k;
 71          Q.push(temp);
 72        }
 73      }
 74    }
 75    cout<< " no "<<endl;
 76  }
 77 
 78   int main()
 79  {
 80     int cas;
 81     // 输入案例的数目
 82     cin>>cas;
 83     while(cas--)
 84    {
 85       // 地图的长与宽
 86       cin>>n>>m;
 87       for( int i= 1;i<=n;i++)
 88      {
 89         for( int j= 1;j<=m;j++)
 90        {
 91          cin>>map[i][j];
 92        }
 93      }
 94       // 这里的x与y坐标值需要转换
 95       cin>>T>>f.y>>f.x>>ej>>ei;
 96       // 首先标注一个不可能的方向,作为初始方向
 97       f.di=- 1;
 98       // 计数拐弯的次数
 99       f.turn= 0;
100      for( int i= 1;i<=n;i++)
101        for( int j= 1;j<=m;j++)
102          // 记录到这里已经拐弯了多少次
103          vis[i][j]= 20;
104     bfs();
105    }
106     return  0;
107  }
108 
109 

 

你可能感兴趣的:(吴昊品游戏核心算法 Round 13 —— 吴昊教你走迷宫(BFS))