zoukankan      html  css  js  c++  java
  • hdu 2821 Pusher

    题目大意:

      在http://www.hacker.org/push网站上,有一个名字叫PusherBoy的游戏。这个游戏给出一个R * C的棋盘,棋盘上有许多堆阻碍前进的箱子。游戏的胜利条件是通过推箱子的方式,清除掉棋盘上所有的箱子。

      现在你需要选择一块空旷的区域作为PusherBoy的初始位置,然后选择一个方向(U代表向上,D代表向下,L代表向左,R代表向右)来推箱子。一旦你选好了一个方向,PusherBoy将一直向前走直到碰到箱子才停下来(不能走出棋盘),然后他从这堆箱子中移除一个箱子(当然咯,如果这一堆中只有一个箱子,移除这个箱子,那么这个地方就清理干净了),同时将剩下的这堆箱子移动到相邻位子。(如果相邻位置也有一堆箱子,那么这两堆箱子将组合成一个新的堆,其数量为前面两堆箱子数量之和)

      不过请注意,如果有堆箱子紧贴着PusherBoy,那么PusherBoy是无法推动它的。也就是说推动箱子的前提是在PusherBoy和箱子之间必须要有一个空隙。举个栗子,看下面的图片。PusherBoy可以向上走,但是不能向下走。(圆圈表示Pusher,正方形表示一堆箱子,嵌套的正方形表示这一堆有两个箱子)如果一堆箱子被推出边界,那么这堆箱子就被认为清理干净了。

                                                  

    输入:

      每个输入中都有几个测试用例。每一个测试用例的前面两行包各包含一个整数,分别是C和R(R,C <= 25)接着是R行,表示这个棋盘。‘.’表示一个空旷的区域,小写字母表示一堆箱子(‘a’表示一个箱子,‘b’表示两个箱子,‘c’表示三个箱子,以此类推)

    输出:

      每个测试用例需要输出三行。前面的两行各包含一个数,分别是x,y表示PusherBoy开始的位置。(0 <= x < R, 0 <= y < C)第三行包含PusherBoy清除所有箱子的移动序列,这个序列由‘U’,‘D’,‘L’,‘R’。任何正确的答案都将通过OJ测试。(Special Judge)

    编程的时候需要注意的地方:

    1、搜索开始的地方必须是'.'

    2、搜索时,需要一个栈结构记录方向;打印结果的时候需要按照队列先进先出的原则输出方向。那么就需要用到双端队列这种数据结构,搜索的时候对队尾进行操作,打印结果的时候对队首进行操作。

    3、需要重点注意的题目条件:(1)箱子被推出边界,就表示箱子被完全清理干净,而不是减去其中一个箱子。(2)PusherBoy与Blocks之间需要有'.',这样PusherBoy才能推动,否则不能推动。

    4、保存好之前的状态(例如:用变量记录这堆箱子的字母以及与它相邻箱子的字母,总箱子数),方便后面的回溯。

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <stdlib.h>
      4 #include <deque>
      5 using namespace std;
      6 
      7 const int N = 30;
      8 const int dir[4][2] = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };//移动的方向 0:上,1;下,2:左,3:右
      9 char board[N][N]; //记录棋盘
     10 int row, col;     //行、列
     11 int blocks;       //记录需要消除的箱子数量
     12 deque<int> result;//用双端队列记录移动方向(搜索的时候,需要一个栈结构管理,输出的时候需要一个队列管理)
     13 
     14 /* 每一个测试,先初始化数据 */
     15 void init(void)
     16 {
     17     blocks = 0;
     18 }
     19 
     20 /* 输入数据 */
     21 void inputBoard(void)
     22 {
     23     for (int i = 0; i < row; ++i)
     24     {
     25         scanf("%s", board[i]);
     26         for (int j = 0; j < col; ++j) //统计需要消灭多少箱子,搜索的时候当箱子数目为0时,表示找到一个结果
     27             if ('.' != board[i][j])
     28                 blocks += board[i][j] - 'a' + 1;
     29     }
     30 }
     31 
     32 /* 判断是否越界 */
     33 inline bool inBoard(int r, int c)
     34 {
     35     return 0 <= r && r < row && 0 <= c && c < col;
     36 }
     37 
     38 /* dfs搜索 */
     39 bool dfs(int r, int c)
     40 {
     41     if (0 == blocks) //board等于0比表示已经清理干净
     42         return true;
     43     for (int i = 0; i < 4; ++i)//上下左右四个方向移动
     44     {
     45         int _r = r + dir[i][0];//向dir[i]方向走第一步
     46         int _c = c + dir[i][1];
     47 
     48         if (false == inBoard(_r, _c)) continue;
     49         if ('.' != board[_r][_c]) continue;//向该方向走的第一步必须是'.'
     50 
     51         result.push_back(i);//记录移动的方向
     52         while (true == inBoard(_r, _c))//沿着该方向走,不能走出边界
     53         {
     54             if ('a' <= board[_r][_c] && board[_r][_c] <= 'z')//碰到字母才处理,否则一直向这个方向走
     55             {
     56 
     57                 int _rr = _r + dir[i][0];//碰到字母后,判断字母相邻位置(_rr, _cc)的情况
     58                 int _cc = _c + dir[i][1];
     59                 char b1 = board[_r][_c]; //记录(_r,_c),(_rr,_cc)的值,回溯的时候还原现场
     60                 char b2 = board[_rr][_cc];
     61 
     62                 if ('a' != board[_r][_c])//(_r,_c)位置为非'a'字母,表明字母降级并移动到相邻位置上。如果为a字母,则箱子直接消失了。
     63                 {
     64                     if (false == inBoard(_rr, _cc))//(_rr,_cc)在边界外边,那么blocks直接推干净
     65                     {
     66                         blocks -= (board[_r][_c] - 'a');
     67                     }
     68                     else if ('a' <= board[_rr][_cc] && board[_rr][_cc] <= 'z')//(_rr,_cc)也为 blocks,那么需要合并
     69                     {
     70                         char tmp = board[_r][_c] - 'a' + board[_rr][_cc];//合并两个blocks,组成一个更大的blokcs
     71                         if (tmp > 'z')
     72                             break; //组成的blocks超过'z'表明这种推法不可取
     73                         else
     74                             board[_rr][_cc] = tmp;
     75                     }
     76                     else //(_r,_c)相邻位置的为 '.'
     77                     {
     78                         board[_rr][_cc] = board[_r][_c] - 1;
     79                     }
     80                 }
     81                 board[_r][_c] = '.';//把(_r,_c)的位置变成 '.'
     82                 --blocks;
     83                 if (true == dfs(_r, _c)) return true;
     84                 ++blocks;
     85                 board[_r][_c] = b1;
     86                 if (true == inBoard(_rr, _cc))
     87                 {
     88                     board[_rr][_cc] = b2;
     89                 }
     90                 else
     91                 {
     92                     blocks += (board[_r][_c] - 'a');
     93                 }
     94                 break;//推blocks失败后,这条路走不通了,要回到原来的位子,换个方向走
     95             }
     96             _r += dir[i][0];
     97             _c += dir[i][1];
     98         }
     99         result.pop_back();
    100     }
    101     return false;
    102 }
    103 
    104 bool dfsTravel( int &i, int &j )
    105 {
    106     for (i = 0; i < row; ++i)
    107         for (j = 0; j < col; ++j)
    108             if ('.' == board[i][j] && true == dfs(i, j))
    109                 return true;
    110     return false;
    111 }
    112 
    113 /* 输出结果 */
    114 void outputResult(int i, int j)
    115 {
    116     printf("%d
    %d
    ", i, j);
    117     while (!result.empty())
    118     {
    119         int tmp = result.front();
    120         switch (tmp)
    121         {
    122         case 0: printf("U"); break;
    123         case 1: printf("D"); break;
    124         case 2: printf("L"); break;
    125         case 3: printf("R"); break;
    126         default: break;
    127         }
    128         result.pop_front();
    129     }
    130     printf("
    ");
    131 }
    132 
    133 int main(void)
    134 {
    135     int i,j;
    136     while (scanf("%d", &col) != EOF)
    137     {
    138         scanf("%d", &row);
    139         init();
    140         inputBoard();
    141         if ( true == dfsTravel(i, j) )
    142             outputResult(i, j);
    143     }
    144     return 0;
    145 }
  • 相关阅读:
    高盛、沃尔玛 题做出来还挂了的吐槽
    amazon师兄debrief
    到所有人家距离之和最短的中点 296. Best Meeting Point
    问问题没人回答的情况怎么办终于有解了
    找名人 277. Find the Celebrity
    数组生存游戏 289. Game of Life
    547. Number of Provinces 省份数量
    428. Serialize and Deserialize Nary Tree 序列化、反序列化n叉树
    alias别名简介和使用
    面试官:线程池执行过程中遇到异常会发生什么,怎样处理? Vincent
  • 原文地址:https://www.cnblogs.com/yongqiang/p/5656207.html
Copyright © 2011-2022 走看看