吴昊品游戏核心算法 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 

 

posted on 2013-02-28 14:39  吴昊系列  阅读(312)  评论(0编辑  收藏  举报

导航